@atproto/syntax 0.5.2 → 0.5.4

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.
@@ -0,0 +1,211 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { describe, expect, test } from 'vitest'
3
+ import { InvalidAtUriError, assertAtUriString, isAtUriString } from '../src'
4
+
5
+ describe('valid interop', () => {
6
+ for (const value of readLines(
7
+ `${__dirname}/../../../interop-test-files/syntax/aturi_syntax_valid.txt`,
8
+ )) {
9
+ testValid(value)
10
+ }
11
+ })
12
+
13
+ describe('invalid interop', () => {
14
+ for (const value of readLines(
15
+ `${__dirname}/../../../interop-test-files/syntax/aturi_syntax_invalid.txt`,
16
+ )) {
17
+ testInvalid(value)
18
+ }
19
+ })
20
+
21
+ describe('custom cases', () => {
22
+ describe('valid spec basics', () => {
23
+ testValid('at://did:plc:asdf123')
24
+ testValid('at://user.bsky.social')
25
+ testValid('at://did:plc:asdf123/com.atproto.feed.post')
26
+ testValid('at://did:plc:asdf123/com.atproto.feed.post/record')
27
+
28
+ testValid('at://did:plc:asdf123#/frag')
29
+ testValid('at://user.bsky.social#/frag')
30
+ testValid('at://did:plc:asdf123/com.atproto.feed.post#/frag')
31
+ testValid('at://did:plc:asdf123/com.atproto.feed.post/record#/frag')
32
+ })
33
+
34
+ describe('invalid spec basics', () => {
35
+ testInvalid('a://did:plc:asdf123')
36
+ testInvalid('at//did:plc:asdf123')
37
+ testInvalid('at:/a/did:plc:asdf123')
38
+ testInvalid('at:/did:plc:asdf123')
39
+ testInvalid('AT://did:plc:asdf123')
40
+ testInvalid('http://did:plc:asdf123')
41
+ testInvalid('://did:plc:asdf123')
42
+ testInvalid('at:did:plc:asdf123')
43
+ testInvalid('at:/did:plc:asdf123')
44
+ testInvalid('at:///did:plc:asdf123')
45
+ testInvalid('at://:/did:plc:asdf123')
46
+ testInvalid('at:/ /did:plc:asdf123')
47
+ testInvalid('at://did:plc:asdf123 ')
48
+ testInvalid('at://did:plc:asdf123/ ')
49
+ testInvalid(' at://did:plc:asdf123')
50
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post ')
51
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post# ')
52
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post#/ ')
53
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post#/frag ')
54
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post#fr ag')
55
+ testInvalid('//did:plc:asdf123')
56
+ testInvalid('at://name')
57
+ testInvalid('at://name.0')
58
+ testInvalid('at://diD:plc:asdf123')
59
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.p@st')
60
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.p$st')
61
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.p%st')
62
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.p&st')
63
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.p()t')
64
+ testInvalid('at://did:plc:asdf123/com.atproto.feed_post')
65
+ testInvalid('at://did:plc:asdf123/-com.atproto.feed.post')
66
+ testInvalid('at://did:plc:asdf@123/com.atproto.feed.post')
67
+
68
+ testInvalid('at://did:plc:asdf123?a')
69
+ testInvalid('at://user.bsky.social?a=B')
70
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post?foo=bar')
71
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/record?q=3')
72
+
73
+ testInvalid('at://did:plc:asdf123?a=b#/frag')
74
+ testInvalid('at://user.bsky.social?a=b#/frag')
75
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post?a=b#/frag')
76
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/record?a=b#/frag')
77
+
78
+ testInvalid('at://DID:plc:asdf123')
79
+ testInvalid('at://user.bsky.123')
80
+ testInvalid('at://bsky')
81
+ testInvalid('at://did:plc:')
82
+ testInvalid('at://did:plc:')
83
+ testInvalid('at://frag')
84
+ })
85
+
86
+ describe('very long strings', () => {
87
+ testValid('at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(512))
88
+ testValid(`at://did:web:x${'.y'.repeat(100)}/com.atproto.feed.post/record`)
89
+ testInvalid(`at://did:plc:${'o'.repeat(8200)}/com.atproto.feed.post/record`)
90
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(513))
91
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(800))
92
+ })
93
+
94
+ describe('invalid collection', () => {
95
+ testInvalid('at://did:plc:asdf123/short/stuff')
96
+ testInvalid('at://did:plc:asdf123/12345')
97
+ })
98
+
99
+ describe('invalid repeated slashes', () => {
100
+ testInvalid('at://user.bsky.social//')
101
+ testInvalid('at://user.bsky.social//com.atproto.feed.post')
102
+ testInvalid('at://user.bsky.social/com.atproto.feed.post//')
103
+ })
104
+
105
+ describe('invalid trailing slashes', () => {
106
+ testInvalid('at://did:plc:asdf123/')
107
+ testInvalid('at://user.bsky.social/')
108
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/')
109
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/')
110
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/#/frag')
111
+ })
112
+
113
+ describe('invalid segment count', () => {
114
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/asdf123/asdf')
115
+ testInvalid('at://did:plc:asdf123/com.atproto.feed.post/asdf123/more/more')
116
+ })
117
+
118
+ describe('valid record key', () => {
119
+ testValid('at://did:plc:asdf123/com.atproto.feed.post/a')
120
+ testValid('at://did:plc:asdf123/com.atproto.feed.post/asdf123')
121
+ })
122
+
123
+ describe('loosely valid trailing slash', () => {
124
+ testLoose('at://did:plc:asdf123/')
125
+ testLoose('at://user.bsky.social/')
126
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/')
127
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/record/')
128
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/record/#/frag')
129
+ })
130
+
131
+ describe('loosely valid record keys', () => {
132
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%23')
133
+
134
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/$@!*)(:,;~.sdf123')
135
+ testLoose("at://did:plc:asdf123/com.atproto.feed.post/~'sdf123")
136
+
137
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/$')
138
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/@')
139
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/!')
140
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/*')
141
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/(')
142
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/,')
143
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/;')
144
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/abc%30123')
145
+
146
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%30')
147
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%3')
148
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%')
149
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%zz')
150
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/%%%')
151
+
152
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/[]')
153
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/foo[')
154
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/bar]')
155
+ testLoose('at://did:plc:asdf123/com.atproto.feed.post/[baz]')
156
+ })
157
+
158
+ describe('valid fragment', () => {
159
+ testValid('at://did:plc:asdf123#/frac')
160
+ })
161
+
162
+ describe('invalid fragment', () => {
163
+ testValid('at://did:plc:asdf123#/com.atproto.feed.post')
164
+ testValid('at://did:plc:asdf123#/com.atproto.feed.post/')
165
+ testValid('at://did:plc:asdf123#/asdf/')
166
+
167
+ testValid('at://did:plc:asdf123/com.atproto.feed.post#/$@!*():,;~.sdf123')
168
+ testValid('at://did:plc:asdf123#/[asfd]')
169
+
170
+ testValid('at://did:plc:asdf123#/$')
171
+ testValid('at://did:plc:asdf123#/*')
172
+ testValid('at://did:plc:asdf123#/;')
173
+ testValid('at://did:plc:asdf123#/,')
174
+
175
+ testInvalid('at://did:plc:asdf123#')
176
+ testInvalid('at://did:plc:asdf123##')
177
+ testInvalid('#at://did:plc:asdf123')
178
+ testInvalid('at://did:plc:asdf123#/asdf#/asdf')
179
+ })
180
+ })
181
+
182
+ function testValid(value: string) {
183
+ test(value, () => {
184
+ expect(isAtUriString(value)).toBe(true)
185
+ expect(isAtUriString(value, { strict: false })).toBe(true)
186
+ expect(() => assertAtUriString(value)).not.toThrow()
187
+ expect(() => assertAtUriString(value, { strict: false })).not.toThrow()
188
+ })
189
+ }
190
+
191
+ function testInvalid(value: string) {
192
+ test(value, () => {
193
+ expect(isAtUriString(value)).toBe(false)
194
+ expect(() => assertAtUriString(value)).toThrow(InvalidAtUriError)
195
+ })
196
+ }
197
+
198
+ function testLoose(value: string) {
199
+ test(value, () => {
200
+ expect(isAtUriString(value)).toBe(false)
201
+ expect(isAtUriString(value, { strict: false })).toBe(true)
202
+ expect(() => assertAtUriString(value)).toThrow()
203
+ expect(() => assertAtUriString(value, { strict: false })).not.toThrow()
204
+ })
205
+ }
206
+
207
+ function readLines(filePath: string): string[] {
208
+ return readFileSync(filePath, 'utf-8')
209
+ .split(/\r?\n/)
210
+ .filter((line) => !line.startsWith('#') && line.length > 0)
211
+ }
@@ -1,12 +1,26 @@
1
- import * as fs from 'node:fs'
2
- import * as readline from 'node:readline'
3
- import { describe, expect, it } from 'vitest'
4
- import { AtUri, ensureValidAtUri, ensureValidAtUriRegex } from '../src'
1
+ import { readFileSync } from 'node:fs'
2
+ import { describe, expect, it, test } from 'vitest'
3
+ import { AtUri } from '../src'
5
4
 
6
5
  describe(AtUri, () => {
7
- it('parses valid at uris', () => {
8
- // input host path query hash
9
- type AtUriTest = [string, string, string, string, string]
6
+ describe('parses valid interop', () => {
7
+ for (const value of readLines(
8
+ `${__dirname}/../../../interop-test-files/syntax/aturi_syntax_valid.txt`,
9
+ )) {
10
+ test(value, () => {
11
+ expect(() => new AtUri(value)).not.toThrow()
12
+ })
13
+ }
14
+ })
15
+
16
+ describe('valid at uris', () => {
17
+ type AtUriTest = [
18
+ input: string,
19
+ host: string,
20
+ path: string,
21
+ query: string,
22
+ hash: string,
23
+ ]
10
24
  const TESTS: AtUriTest[] = [
11
25
  ['foo.com', 'foo.com', '', '', ''],
12
26
  ['at://foo.com', 'foo.com', '', '', ''],
@@ -246,15 +260,17 @@ describe(AtUri, () => {
246
260
  '',
247
261
  ],
248
262
  ]
249
- for (const [uri, hostname, pathname, search, hash] of TESTS) {
250
- const urip = new AtUri(uri)
251
- expect(urip.protocol).toBe('at:')
252
- expect(urip.host).toBe(hostname)
253
- expect(urip.hostname).toBe(hostname)
254
- expect(urip.origin).toBe(`at://${hostname}`)
255
- expect(urip.pathname).toBe(pathname)
256
- expect(urip.search).toBe(search)
257
- expect(urip.hash).toBe(hash)
263
+ for (const [input, host, path, search, hash] of TESTS) {
264
+ test(input, () => {
265
+ const urip = new AtUri(input)
266
+ expect(urip.protocol).toBe('at:')
267
+ expect(urip.host).toBe(host)
268
+ expect(urip.hostname).toBe(host)
269
+ expect(urip.origin).toBe(`at://${host}`)
270
+ expect(urip.pathname).toBe(path)
271
+ expect(urip.search).toBe(search)
272
+ expect(urip.hash).toBe(hash)
273
+ })
258
274
  }
259
275
  })
260
276
 
@@ -278,16 +294,16 @@ describe(AtUri, () => {
278
294
 
279
295
  it('supports modifications', () => {
280
296
  const urip = new AtUri('at://foo.com')
281
- expect(urip.toString()).toBe('at://foo.com/')
297
+ expect(urip.toString()).toBe('at://foo.com')
282
298
 
283
299
  urip.host = 'bar.com'
284
- expect(urip.toString()).toBe('at://bar.com/')
300
+ expect(urip.toString()).toBe('at://bar.com')
285
301
  urip.host = 'did:web:localhost%3A1234'
286
- expect(urip.toString()).toBe('at://did:web:localhost%3A1234/')
302
+ expect(urip.toString()).toBe('at://did:web:localhost%3A1234')
287
303
  urip.host = 'foo.com'
288
304
 
289
305
  urip.pathname = '/'
290
- expect(urip.toString()).toBe('at://foo.com/')
306
+ expect(urip.toString()).toBe('at://foo.com')
291
307
  urip.pathname = '/foo'
292
308
  expect(urip.toString()).toBe('at://foo.com/foo')
293
309
  urip.pathname = 'foo'
@@ -316,11 +332,9 @@ describe(AtUri, () => {
316
332
  expect(urip.toString()).toBe('at://foo.com/foo?foo=bar&baz=buux#hash')
317
333
  })
318
334
 
319
- it('supports relative URIs', () => {
320
- // input path query hash
321
- type AtUriTest = [string, string, string, string]
335
+ describe('relative URIs', () => {
336
+ type AtUriTest = [input: string, path: string, search: string, hash: string]
322
337
  const TESTS: AtUriTest[] = [
323
- // input hostname pathname query hash
324
338
  ['', '', '', ''],
325
339
  ['/', '/', '', ''],
326
340
  ['/foo', '/foo', '', ''],
@@ -347,180 +361,23 @@ describe(AtUri, () => {
347
361
  ]
348
362
 
349
363
  for (const base of BASES) {
350
- const basep = new AtUri(base)
351
- for (const [relative, pathname, search, hash] of TESTS) {
352
- const urip = new AtUri(relative, base)
353
- expect(urip.protocol).toBe('at:')
354
- expect(urip.host).toBe(basep.host)
355
- expect(urip.hostname).toBe(basep.hostname)
356
- expect(urip.origin).toBe(basep.origin)
357
- expect(urip.pathname).toBe(pathname)
358
- expect(urip.search).toBe(search)
359
- expect(urip.hash).toBe(hash)
360
- }
364
+ describe(base, () => {
365
+ for (const [input, path, search, hash] of TESTS) {
366
+ test(input, () => {
367
+ const baseUri = new AtUri(base)
368
+ const uri = new AtUri(input, base)
369
+ expect(uri.protocol).toBe('at:')
370
+ expect(uri.host).toBe(baseUri.host)
371
+ expect(uri.hostname).toBe(baseUri.hostname)
372
+ expect(uri.origin).toBe(baseUri.origin)
373
+ expect(uri.pathname).toBe(path)
374
+ expect(uri.search).toBe(search)
375
+ expect(uri.hash).toBe(hash)
376
+ })
377
+ }
378
+ })
361
379
  }
362
380
  })
363
- })
364
-
365
- describe('AtUri validation', () => {
366
- const expectValid = (h: string) => {
367
- ensureValidAtUri(h)
368
- ensureValidAtUriRegex(h)
369
- }
370
- const expectInvalid = (h: string) => {
371
- expect(() => ensureValidAtUri(h)).toThrow()
372
- expect(() => ensureValidAtUriRegex(h)).toThrow()
373
- }
374
-
375
- it('enforces spec basics', () => {
376
- expectValid('at://did:plc:asdf123')
377
- expectValid('at://user.bsky.social')
378
- expectValid('at://did:plc:asdf123/com.atproto.feed.post')
379
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/record')
380
-
381
- expectValid('at://did:plc:asdf123#/frag')
382
- expectValid('at://user.bsky.social#/frag')
383
- expectValid('at://did:plc:asdf123/com.atproto.feed.post#/frag')
384
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/record#/frag')
385
-
386
- expectInvalid('a://did:plc:asdf123')
387
- expectInvalid('at//did:plc:asdf123')
388
- expectInvalid('at:/a/did:plc:asdf123')
389
- expectInvalid('at:/did:plc:asdf123')
390
- expectInvalid('AT://did:plc:asdf123')
391
- expectInvalid('http://did:plc:asdf123')
392
- expectInvalid('://did:plc:asdf123')
393
- expectInvalid('at:did:plc:asdf123')
394
- expectInvalid('at:/did:plc:asdf123')
395
- expectInvalid('at:///did:plc:asdf123')
396
- expectInvalid('at://:/did:plc:asdf123')
397
- expectInvalid('at:/ /did:plc:asdf123')
398
- expectInvalid('at://did:plc:asdf123 ')
399
- expectInvalid('at://did:plc:asdf123/ ')
400
- expectInvalid(' at://did:plc:asdf123')
401
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post ')
402
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post# ')
403
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#/ ')
404
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#/frag ')
405
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#fr ag')
406
- expectInvalid('//did:plc:asdf123')
407
- expectInvalid('at://name')
408
- expectInvalid('at://name.0')
409
- expectInvalid('at://diD:plc:asdf123')
410
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.p@st')
411
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.p$st')
412
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.p%st')
413
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.p&st')
414
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.p()t')
415
- expectInvalid('at://did:plc:asdf123/com.atproto.feed_post')
416
- expectInvalid('at://did:plc:asdf123/-com.atproto.feed.post')
417
- expectInvalid('at://did:plc:asdf@123/com.atproto.feed.post')
418
-
419
- expectInvalid('at://DID:plc:asdf123')
420
- expectInvalid('at://user.bsky.123')
421
- expectInvalid('at://bsky')
422
- expectInvalid('at://did:plc:')
423
- expectInvalid('at://did:plc:')
424
- expectInvalid('at://frag')
425
-
426
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(800))
427
- expectInvalid(
428
- 'at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(8200),
429
- )
430
- })
431
-
432
- it('has specified behavior on edge cases', () => {
433
- expectInvalid('at://user.bsky.social//')
434
- expectInvalid('at://user.bsky.social//com.atproto.feed.post')
435
- expectInvalid('at://user.bsky.social/com.atproto.feed.post//')
436
- expectInvalid(
437
- 'at://did:plc:asdf123/com.atproto.feed.post/asdf123/more/more',
438
- )
439
- expectInvalid('at://did:plc:asdf123/short/stuff')
440
- expectInvalid('at://did:plc:asdf123/12345')
441
- })
442
-
443
- it('enforces no trailing slashes', () => {
444
- expectValid('at://did:plc:asdf123')
445
- expectInvalid('at://did:plc:asdf123/')
446
-
447
- expectValid('at://user.bsky.social')
448
- expectInvalid('at://user.bsky.social/')
449
-
450
- expectValid('at://did:plc:asdf123/com.atproto.feed.post')
451
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/')
452
-
453
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/record')
454
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/')
455
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/#/frag')
456
- })
457
-
458
- it('enforces strict paths', () => {
459
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/asdf123')
460
- expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/asdf123/asdf')
461
- })
462
-
463
- it('is very permissive about record keys', () => {
464
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/asdf123')
465
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/a')
466
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%23')
467
-
468
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/$@!*)(:,;~.sdf123')
469
- expectValid("at://did:plc:asdf123/com.atproto.feed.post/~'sdf123")
470
-
471
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/$')
472
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/@')
473
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/!')
474
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/*')
475
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/(')
476
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/,')
477
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/;')
478
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/abc%30123')
479
- })
480
-
481
- it('is probably too permissive about URL encoding', () => {
482
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%30')
483
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%3')
484
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%')
485
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%zz')
486
- expectValid('at://did:plc:asdf123/com.atproto.feed.post/%%%')
487
- })
488
-
489
- it('is very permissive about fragments', () => {
490
- expectValid('at://did:plc:asdf123#/frac')
491
-
492
- expectInvalid('at://did:plc:asdf123#')
493
- expectInvalid('at://did:plc:asdf123##')
494
- expectInvalid('#at://did:plc:asdf123')
495
- expectInvalid('at://did:plc:asdf123#/asdf#/asdf')
496
-
497
- expectValid('at://did:plc:asdf123#/com.atproto.feed.post')
498
- expectValid('at://did:plc:asdf123#/com.atproto.feed.post/')
499
- expectValid('at://did:plc:asdf123#/asdf/')
500
-
501
- expectValid('at://did:plc:asdf123/com.atproto.feed.post#/$@!*():,;~.sdf123')
502
- expectValid('at://did:plc:asdf123#/[asfd]')
503
-
504
- expectValid('at://did:plc:asdf123#/$')
505
- expectValid('at://did:plc:asdf123#/*')
506
- expectValid('at://did:plc:asdf123#/;')
507
- expectValid('at://did:plc:asdf123#/,')
508
- })
509
-
510
- it('conforms to interop valid ATURIs', () => {
511
- const lineReader = readline.createInterface({
512
- input: fs.createReadStream(
513
- `${__dirname}/interop-files/aturi_syntax_valid.txt`,
514
- ),
515
- terminal: false,
516
- })
517
- lineReader.on('line', (line) => {
518
- if (line.startsWith('#') || line.length === 0) {
519
- return
520
- }
521
- expectValid(line)
522
- })
523
- })
524
381
 
525
382
  it('properly checks that the did property is a valid did', () => {
526
383
  const urip = new AtUri('at://did:example:123')
@@ -568,6 +425,10 @@ describe('AtUri validation', () => {
568
425
  expect(urip.rkey).toBe('not a valid rkey')
569
426
  expect(() => urip.rkeySafe).toThrow()
570
427
  })
571
-
572
- // NOTE: this package is currently more permissive than spec about AT URIs, so invalid cases are not errors
573
428
  })
429
+
430
+ function readLines(filePath: string): string[] {
431
+ return readFileSync(filePath, 'utf-8')
432
+ .split(/\r?\n/)
433
+ .filter((line) => !line.startsWith('#') && line.length > 0)
434
+ }
@@ -128,9 +128,28 @@ describe(normalizeDatetime, () => {
128
128
  expect(normalizeDatetime('1985-04-12T10:20:50.1+01:00')).toEqual(
129
129
  '1985-04-12T09:20:50.100Z',
130
130
  )
131
+ expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56+1212')).toEqual(
132
+ '1999-01-02T00:22:56.000Z',
133
+ )
134
+ expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56Z')).toEqual(
135
+ '1999-01-02T12:34:56.000Z',
136
+ )
131
137
  expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 GMT')).toEqual(
132
138
  '1999-01-02T12:34:56.000Z',
133
139
  )
140
+ expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 PST')).toEqual(
141
+ '1999-01-02T20:34:56.000Z',
142
+ )
143
+ expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 EST')).toEqual(
144
+ '1999-01-02T17:34:56.000Z',
145
+ )
146
+ // @NOTE "(Central European Standard Time)" is not used by "Date" to infer
147
+ // the right timezone offset, so these will be parsed as UTC
148
+ expect(
149
+ normalizeDatetime(
150
+ 'Fri, 02 Jan 1999 12:34:56 (Central European Standard Time)',
151
+ ),
152
+ ).toEqual('1999-01-02T12:34:56.000Z')
134
153
  expect(normalizeDatetime('0001-01-01T00:00:00+01:00')).toEqual(
135
154
  '0000-12-31T23:00:00.000Z',
136
155
  )
@@ -170,6 +189,9 @@ describe(normalizeDatetime, () => {
170
189
  expect(() => normalizeDatetime('1999-19-39T23:20:50.123Z')).toThrow(
171
190
  InvalidDatetimeError,
172
191
  )
192
+ expect(() => normalizeDatetime('Fri, 02 Jan 1999 12:34:56 AFT')).toThrow(
193
+ InvalidDatetimeError,
194
+ )
173
195
  expect(() => normalizeDatetime('-000001-12-31T23:00:00.000Z')).toThrow(
174
196
  InvalidDatetimeError,
175
197
  )
@@ -1 +1 @@
1
- {"root":["./src/at-identifier.ts","./src/aturi.ts","./src/aturi_validation.ts","./src/datetime.ts","./src/did.ts","./src/handle.ts","./src/index.ts","./src/language.ts","./src/nsid.ts","./src/recordkey.ts","./src/tid.ts","./src/uri.ts"],"version":"5.8.2"}
1
+ {"root":["./src/at-identifier.ts","./src/aturi.ts","./src/aturi_validation.ts","./src/datetime.ts","./src/did.ts","./src/handle.ts","./src/index.ts","./src/language.ts","./src/nsid.ts","./src/recordkey.ts","./src/tid.ts","./src/uri.ts","./src/lib/result.ts"],"version":"5.8.2"}