@atproto/syntax 0.6.3 → 0.6.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/at-identifier.d.ts +2 -2
  3. package/dist/at-identifier.d.ts.map +1 -1
  4. package/dist/at-identifier.js.map +1 -1
  5. package/dist/aturi.d.ts +5 -5
  6. package/dist/aturi.d.ts.map +1 -1
  7. package/dist/aturi.js +1 -1
  8. package/dist/aturi.js.map +1 -1
  9. package/dist/aturi_validation.d.ts +3 -3
  10. package/dist/aturi_validation.d.ts.map +1 -1
  11. package/dist/aturi_validation.js.map +1 -1
  12. package/dist/language.js +1 -1
  13. package/dist/language.js.map +1 -1
  14. package/dist/nsid.d.ts +1 -1
  15. package/dist/nsid.d.ts.map +1 -1
  16. package/dist/nsid.js.map +1 -1
  17. package/package.json +15 -14
  18. package/benchmark.cjs +0 -208
  19. package/src/at-identifier.ts +0 -104
  20. package/src/aturi.ts +0 -197
  21. package/src/aturi_validation.ts +0 -321
  22. package/src/datetime.ts +0 -369
  23. package/src/did.ts +0 -71
  24. package/src/handle.ts +0 -128
  25. package/src/index.ts +0 -10
  26. package/src/language.ts +0 -39
  27. package/src/lib/result.ts +0 -11
  28. package/src/nsid.ts +0 -182
  29. package/src/recordkey.ts +0 -51
  30. package/src/tid.ts +0 -22
  31. package/src/uri.ts +0 -5
  32. package/tests/aturi-string.test.ts +0 -223
  33. package/tests/aturi.test.ts +0 -428
  34. package/tests/datetime.test.ts +0 -280
  35. package/tests/did.test.ts +0 -104
  36. package/tests/handle.test.ts +0 -239
  37. package/tests/language.test.ts +0 -88
  38. package/tests/nsid.test.ts +0 -174
  39. package/tests/recordkey.test.ts +0 -43
  40. package/tests/tid.test.ts +0 -43
  41. package/tsconfig.build.json +0 -12
  42. package/tsconfig.build.tsbuildinfo +0 -1
  43. package/tsconfig.json +0 -7
  44. package/tsconfig.tests.json +0 -8
  45. package/vitest.config.ts +0 -5
@@ -1,280 +0,0 @@
1
- import * as fs from 'node:fs'
2
- import { describe, expect, it, test } from 'vitest'
3
- import {
4
- InvalidDatetimeError,
5
- ensureValidDatetime,
6
- isDatetimeString,
7
- isDatetimeStringLenient,
8
- normalizeDatetime,
9
- normalizeDatetimeAlways,
10
- } from '../src/index.js'
11
-
12
- const interopValid = readLines(
13
- `${__dirname}/interop-files/datetime_syntax_valid.txt`,
14
- )
15
- const interopInvalidSyntax = readLines(
16
- `${__dirname}/interop-files/datetime_syntax_invalid.txt`,
17
- )
18
- const interopInvalidParse = readLines(
19
- `${__dirname}/interop-files/datetime_parse_invalid.txt`,
20
- )
21
-
22
- // These strings come from the test suite in "@atproto/lexicon", kept around
23
- // to ensure compatibility with legacy implementation.
24
- const legacyValid = [
25
- '2022-12-12T00:50:36.809Z',
26
- '2022-12-12T00:50:36Z',
27
- '2022-12-12T00:50:36.8Z',
28
- '2022-12-12T00:50:36.80Z',
29
- '2022-12-12T00:50:36+00:00',
30
- '2022-12-12T00:50:36.8+00:00',
31
- '2022-12-11T19:50:36-05:00',
32
- '2022-12-11T19:50:36.8-05:00',
33
- '2022-12-11T19:50:36.80-05:00',
34
- '2022-12-11T19:50:36.809-05:00',
35
- ]
36
-
37
- describe(ensureValidDatetime, () => {
38
- describe('Interop valid', () => {
39
- test.each(interopValid)('%s', (dt) => {
40
- expect(() => ensureValidDatetime(dt)).not.toThrow()
41
- })
42
- })
43
-
44
- describe('Interop invalid syntax', () => {
45
- test.each(interopInvalidSyntax)('%s', (dt) => {
46
- expect(() => ensureValidDatetime(dt)).toThrow(InvalidDatetimeError)
47
- })
48
- })
49
-
50
- describe('Interop invalid parse', () => {
51
- test.each(interopInvalidParse)('%s', (dt) => {
52
- expect(() => ensureValidDatetime(dt)).toThrow(InvalidDatetimeError)
53
- })
54
- })
55
-
56
- it('rejects datetime that normalizes past year 9999 due to negative offset', () => {
57
- // 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
58
- // UTC advances it to 10000-01-01T00:00:00Z, which is out of range
59
- expect(() => ensureValidDatetime('9999-12-31T23:59:00-00:01')).toThrow(
60
- InvalidDatetimeError,
61
- )
62
- })
63
- })
64
-
65
- describe(isDatetimeString, () => {
66
- describe('Interop valid', () => {
67
- test.each(interopValid)('%s', (dt) => {
68
- expect(isDatetimeString(dt)).toBe(true)
69
- })
70
- })
71
-
72
- describe('Interop invalid syntax', () => {
73
- test.each(interopInvalidSyntax)('%s', (dt) => {
74
- expect(isDatetimeString(dt)).toBe(false)
75
- })
76
- })
77
-
78
- describe('Interop invalid parse', () => {
79
- test.each(interopInvalidParse)('%s', (dt) => {
80
- expect(isDatetimeString(dt)).toBe(false)
81
- })
82
- })
83
-
84
- describe('succeeds on legacy valid', () => {
85
- test.each(legacyValid)('%s', (dt) => {
86
- expect(isDatetimeString(dt)).toBe(true)
87
- })
88
- })
89
-
90
- it('rejects datetime that normalizes past year 9999 due to negative offset', () => {
91
- // 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
92
- // UTC advances it to 10000-01-01T00:00:00Z, which is out of range
93
- expect(isDatetimeString('9999-12-31T23:59:00-00:01')).toBe(false)
94
- })
95
- })
96
-
97
- describe(isDatetimeStringLenient, () => {
98
- describe('Interop valid', () => {
99
- test.each(interopValid)('%s', (dt) => {
100
- expect(isDatetimeStringLenient(dt)).toBe(true)
101
- })
102
- })
103
-
104
- // Because of it leniency, the "isDatetimeStringLenient" implementation does
105
- // not fail on some of the invalid syntax cases, so these tests are skipped.
106
- describe.skip('Interop invalid syntax', () => {
107
- test.each(interopInvalidSyntax)('%s', (dt) => {
108
- expect(isDatetimeStringLenient(dt)).toBe(false)
109
- })
110
- })
111
-
112
- describe('Interop invalid parse', () => {
113
- test.each(interopInvalidParse)('%s', (dt) => {
114
- expect(isDatetimeStringLenient(dt)).toBe(false)
115
- })
116
- })
117
-
118
- describe('Legacy valid', () => {
119
- test.each(legacyValid)('%s', (dt) => {
120
- expect(isDatetimeStringLenient(dt)).toBe(true)
121
- })
122
- })
123
- })
124
-
125
- describe(normalizeDatetime, () => {
126
- describe('Interop valid', () => {
127
- test.each(interopValid)('%s', (dt) => {
128
- expect(() => normalizeDatetime(dt)).not.toThrow()
129
- })
130
- })
131
-
132
- // @NOTE Normalize will actually succeed on some of the invalid syntax cases,
133
- // because it is more lenient than the regex validation.
134
- describe.skip('Interop invalid syntax', () => {
135
- test.each(interopInvalidSyntax)('%s', (dt) => {
136
- expect(() => normalizeDatetime(dt)).toThrow(InvalidDatetimeError)
137
- })
138
- })
139
-
140
- describe('Interop invalid parse', () => {
141
- test.each(interopInvalidParse)('%s', (dt) => {
142
- expect(() => normalizeDatetime(dt)).toThrow(InvalidDatetimeError)
143
- })
144
- })
145
-
146
- it('normalizes valid input', () => {
147
- expect(normalizeDatetime('1234-04-12T23:20:50Z')).toEqual(
148
- '1234-04-12T23:20:50.000Z',
149
- )
150
- expect(normalizeDatetime('1985-04-12T23:20:50Z')).toEqual(
151
- '1985-04-12T23:20:50.000Z',
152
- )
153
- expect(normalizeDatetime('1985-04-12T23:20:50.123')).toEqual(
154
- '1985-04-12T23:20:50.123Z',
155
- )
156
- expect(normalizeDatetime('1985-04-12 23:20:50.123')).toEqual(
157
- '1985-04-12T23:20:50.123Z',
158
- )
159
- expect(normalizeDatetime('1985-04-12T10:20:50.1+01:00')).toEqual(
160
- '1985-04-12T09:20:50.100Z',
161
- )
162
- expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56+1212')).toEqual(
163
- '1999-01-02T00:22:56.000Z',
164
- )
165
- expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56Z')).toEqual(
166
- '1999-01-02T12:34:56.000Z',
167
- )
168
- expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 GMT')).toEqual(
169
- '1999-01-02T12:34:56.000Z',
170
- )
171
- expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 PST')).toEqual(
172
- '1999-01-02T20:34:56.000Z',
173
- )
174
- expect(normalizeDatetime('Fri, 02 Jan 1999 12:34:56 EST')).toEqual(
175
- '1999-01-02T17:34:56.000Z',
176
- )
177
- // @NOTE "(Central European Standard Time)" is not used by "Date" to infer
178
- // the right timezone offset, so these will be parsed as UTC
179
- expect(
180
- normalizeDatetime(
181
- 'Fri, 02 Jan 1999 12:34:56 (Central European Standard Time)',
182
- ),
183
- ).toEqual('1999-01-02T12:34:56.000Z')
184
- expect(normalizeDatetime('0001-01-01T00:00:00+01:00')).toEqual(
185
- '0000-12-31T23:00:00.000Z',
186
- )
187
- })
188
-
189
- it('accepts years 1-9', () => {
190
- expect(normalizeDatetime('0009-12-31T23:59:59Z')).toEqual(
191
- '0009-12-31T23:59:59.000Z',
192
- )
193
- expect(normalizeDatetime('0005-06-15T12:00:00Z')).toEqual(
194
- '0005-06-15T12:00:00.000Z',
195
- )
196
- expect(normalizeDatetime('0001-01-01T00:00:00Z')).toEqual(
197
- '0001-01-01T00:00:00.000Z',
198
- )
199
- expect(normalizeDatetime('0002-03-04T05:06:07.890Z')).toEqual(
200
- '0002-03-04T05:06:07.890Z',
201
- )
202
- })
203
-
204
- it('accepts single-digit years with leading zeros', () => {
205
- expect(normalizeDatetime('0007-01-01T00:00:00Z')).toEqual(
206
- '0007-01-01T00:00:00.000Z',
207
- )
208
- })
209
-
210
- it('accepts year 1 with timezone offsets', () => {
211
- // Year 1 with negative offset stays in valid range
212
- expect(normalizeDatetime('0001-12-31T23:00:00-01:00')).toEqual(
213
- '0002-01-01T00:00:00.000Z',
214
- )
215
- })
216
-
217
- it('throws on invalid input', () => {
218
- expect(() => normalizeDatetime('')).toThrow(InvalidDatetimeError)
219
- expect(() => normalizeDatetime('blah')).toThrow(InvalidDatetimeError)
220
- expect(() => normalizeDatetime('1999-19-39T23:20:50.123Z')).toThrow(
221
- InvalidDatetimeError,
222
- )
223
- expect(() => normalizeDatetime('Fri, 02 Jan 1999 12:34:56 AFT')).toThrow(
224
- InvalidDatetimeError,
225
- )
226
- expect(() => normalizeDatetime('-000001-12-31T23:00:00.000Z')).toThrow(
227
- InvalidDatetimeError,
228
- )
229
- expect(() => normalizeDatetime('0000-01-01T00:00:00+01:00')).toThrow(
230
- InvalidDatetimeError,
231
- )
232
- // 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
233
- // UTC advances it to 10000-01-01T00:00:00Z, which is out of range
234
- expect(() => normalizeDatetime('9999-12-31T23:59:00-00:01')).toThrow(
235
- InvalidDatetimeError,
236
- )
237
- })
238
- })
239
-
240
- describe(normalizeDatetimeAlways, () => {
241
- it('normalizes valid input', () => {
242
- expect(normalizeDatetimeAlways('1985-04-12T23:20:50Z')).toEqual(
243
- '1985-04-12T23:20:50.000Z',
244
- )
245
- })
246
-
247
- it('normalizes invalid input', () => {
248
- expect(normalizeDatetimeAlways('blah')).toEqual('1970-01-01T00:00:00.000Z')
249
- expect(normalizeDatetimeAlways('0000-01-01T00:00:00+01:00')).toEqual(
250
- '1970-01-01T00:00:00.000Z',
251
- )
252
- })
253
-
254
- describe('Interop valid', () => {
255
- test.each(interopValid)('%s', (dt) => {
256
- // @NOTE we can't test the returned value as some will normalize while others won't.
257
- expect(() => normalizeDatetimeAlways(dt)).not.toThrow()
258
- })
259
- })
260
-
261
- describe('Interop invalid syntax', () => {
262
- test.each(interopInvalidSyntax)('%s', (dt) => {
263
- // @NOTE we can't test the returned value as some will normalize while others won't.
264
- expect(() => normalizeDatetimeAlways(dt)).not.toThrow()
265
- })
266
- })
267
-
268
- describe('Interop invalid parse', () => {
269
- test.each(interopInvalidParse)('%s', (dt) => {
270
- expect(normalizeDatetimeAlways(dt)).toEqual('1970-01-01T00:00:00.000Z')
271
- })
272
- })
273
- })
274
-
275
- function readLines(filePath: string): string[] {
276
- return fs
277
- .readFileSync(filePath, 'utf-8')
278
- .split(/\r?\n/)
279
- .filter((line) => !line.startsWith('#') && line.length > 0)
280
- }
package/tests/did.test.ts DELETED
@@ -1,104 +0,0 @@
1
- import * as fs from 'node:fs'
2
- import * as readline from 'node:readline'
3
- import { describe, expect, it } from 'vitest'
4
- import {
5
- InvalidDidError,
6
- ensureValidDid,
7
- ensureValidDidRegex,
8
- } from '../src/index.js'
9
-
10
- describe('DID permissive validation', () => {
11
- const expectValid = (h: string) => {
12
- ensureValidDid(h)
13
- ensureValidDidRegex(h)
14
- }
15
- const expectInvalid = (h: string) => {
16
- expect(() => ensureValidDid(h)).toThrow(InvalidDidError)
17
- expect(() => ensureValidDidRegex(h)).toThrow(InvalidDidError)
18
- }
19
-
20
- it('enforces spec details', () => {
21
- expectValid('did:method:val')
22
- expectValid('did:method:VAL')
23
- expectValid('did:method:val123')
24
- expectValid('did:method:123')
25
- expectValid('did:method:val-two')
26
- expectValid('did:method:val_two')
27
- expectValid('did:method:val.two')
28
- expectValid('did:method:val:two')
29
- expectValid('did:method:val%BB')
30
-
31
- expectInvalid('did')
32
- expectInvalid('didmethodval')
33
- expectInvalid('method:did:val')
34
- expectInvalid('did:method:')
35
- expectInvalid('didmethod:val')
36
- expectInvalid('did:methodval')
37
- expectInvalid(':did:method:val')
38
- expectInvalid('did.method.val')
39
- expectInvalid('did:method:val:')
40
- expectInvalid('did:method:val%')
41
- expectInvalid('DID:method:val')
42
- expectInvalid('did:METHOD:val')
43
- expectInvalid('did:m123:val')
44
-
45
- expectValid('did:method:' + 'v'.repeat(240))
46
- expectInvalid('did:method:' + 'v'.repeat(8500))
47
-
48
- expectValid('did:m:v')
49
- expectValid('did:method::::val')
50
- expectValid('did:method:-')
51
- expectValid('did:method:-:_:.:%ab')
52
- expectValid('did:method:.')
53
- expectValid('did:method:_')
54
- expectValid('did:method::.')
55
-
56
- expectInvalid('did:method:val/two')
57
- expectInvalid('did:method:val?two')
58
- expectInvalid('did:method:val#two')
59
- expectInvalid('did:method:val%')
60
-
61
- expectValid(
62
- 'did:onion:2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid',
63
- )
64
- })
65
-
66
- it('allows some real DID values', () => {
67
- expectValid('did:example:123456789abcdefghi')
68
- expectValid('did:plc:7iza6de2dwap2sbkpav7c6c6')
69
- expectValid('did:web:example.com')
70
- expectValid('did:web:localhost%3A1234')
71
- expectValid('did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N')
72
- expectValid('did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a')
73
- })
74
-
75
- it('conforms to interop valid DIDs', () => {
76
- const lineReader = readline.createInterface({
77
- input: fs.createReadStream(
78
- `${__dirname}/interop-files/did_syntax_valid.txt`,
79
- ),
80
- terminal: false,
81
- })
82
- lineReader.on('line', (line) => {
83
- if (line.startsWith('#') || line.length === 0) {
84
- return
85
- }
86
- expectValid(line)
87
- })
88
- })
89
-
90
- it('conforms to interop invalid DIDs', () => {
91
- const lineReader = readline.createInterface({
92
- input: fs.createReadStream(
93
- `${__dirname}/interop-files/did_syntax_invalid.txt`,
94
- ),
95
- terminal: false,
96
- })
97
- lineReader.on('line', (line) => {
98
- if (line.startsWith('#') || line.length === 0) {
99
- return
100
- }
101
- expectInvalid(line)
102
- })
103
- })
104
- })
@@ -1,239 +0,0 @@
1
- import * as fs from 'node:fs'
2
- import * as readline from 'node:readline'
3
- import { describe, expect, it } from 'vitest'
4
- import {
5
- InvalidHandleError,
6
- ensureValidHandle,
7
- ensureValidHandleRegex,
8
- normalizeAndEnsureValidHandle,
9
- } from '../src/index.js'
10
-
11
- describe('handle validation', () => {
12
- const expectValid = (h: string) => {
13
- ensureValidHandle(h)
14
- ensureValidHandleRegex(h)
15
- }
16
- const expectInvalid = (h: string) => {
17
- expect(() => ensureValidHandle(h)).toThrow(InvalidHandleError)
18
- expect(() => ensureValidHandleRegex(h)).toThrow(InvalidHandleError)
19
- }
20
-
21
- it('allows valid handles', () => {
22
- expectValid('A.ISI.EDU')
23
- expectValid('XX.LCS.MIT.EDU')
24
- expectValid('SRI-NIC.ARPA')
25
- expectValid('john.test')
26
- expectValid('jan.test')
27
- expectValid('a234567890123456789.test')
28
- expectValid('john2.test')
29
- expectValid('john-john.test')
30
- expectValid('john.bsky.app')
31
- expectValid('jo.hn')
32
- expectValid('a.co')
33
- expectValid('a.org')
34
- expectValid('joh.n')
35
- expectValid('j0.h0')
36
- const longHandle =
37
- 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(8) + '.test'
38
- expect(longHandle.length).toEqual(253)
39
- expectValid(longHandle)
40
- expectValid('short.' + 'o'.repeat(63) + '.test')
41
- expectValid('jaymome-johnber123456.test')
42
- expectValid('jay.mome-johnber123456.test')
43
- expectValid('john.test.bsky.app')
44
-
45
- // NOTE: this probably isn't ever going to be a real domain, but my read of
46
- // the RFC is that it would be possible
47
- expectValid('john.t')
48
- })
49
-
50
- // NOTE: we may change this at the proto level; currently only disallowed at
51
- // the registration level
52
- it('allows .local and .arpa handles (proto-level)', () => {
53
- expectValid('laptop.local')
54
- expectValid('laptop.arpa')
55
- })
56
-
57
- it('allows punycode handles', () => {
58
- expectValid('xn--ls8h.test') // 💩.test
59
- expectValid('xn--bcher-kva.tld') // bücher.tld
60
- expectValid('xn--3jk.com')
61
- expectValid('xn--w3d.com')
62
- expectValid('xn--vqb.com')
63
- expectValid('xn--ppd.com')
64
- expectValid('xn--cs9a.com')
65
- expectValid('xn--8r9a.com')
66
- expectValid('xn--cfd.com')
67
- expectValid('xn--5jk.com')
68
- expectValid('xn--2lb.com')
69
- })
70
-
71
- it('allows onion (Tor) handles', () => {
72
- expectValid('expyuzz4wqqyqhjn.onion')
73
- expectValid('friend.expyuzz4wqqyqhjn.onion')
74
- expectValid(
75
- 'g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion',
76
- )
77
- expectValid(
78
- 'friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion',
79
- )
80
- expectValid(
81
- 'friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion',
82
- )
83
- expectValid(
84
- '2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion',
85
- )
86
- expectValid(
87
- 'friend.2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion',
88
- )
89
- })
90
-
91
- it('throws on invalid handles', () => {
92
- expectInvalid('did:thing.test')
93
- expectInvalid('did:thing')
94
- expectInvalid('john-.test')
95
- expectInvalid('john.0')
96
- expectInvalid('john.-')
97
- expectInvalid('short.' + 'o'.repeat(64) + '.test')
98
- expectInvalid('short' + '.loooooooooooooooooooooooong'.repeat(10) + '.test')
99
- const longHandle =
100
- 'shooooort' + '.loooooooooooooooooooooooooong'.repeat(8) + '.test'
101
- expect(longHandle.length).toEqual(254)
102
- expectInvalid(longHandle)
103
- expectInvalid('xn--bcher-.tld')
104
- expectInvalid('john..test')
105
- expectInvalid('jo_hn.test')
106
- expectInvalid('-john.test')
107
- expectInvalid('.john.test')
108
- expectInvalid('jo!hn.test')
109
- expectInvalid('jo%hn.test')
110
- expectInvalid('jo&hn.test')
111
- expectInvalid('jo@hn.test')
112
- expectInvalid('jo*hn.test')
113
- expectInvalid('jo|hn.test')
114
- expectInvalid('jo:hn.test')
115
- expectInvalid('jo/hn.test')
116
- expectInvalid('john💩.test')
117
- expectInvalid('bücher.test')
118
- expectInvalid('john .test')
119
- expectInvalid('john.test.')
120
- expectInvalid('john')
121
- expectInvalid('john.')
122
- expectInvalid('.john')
123
- expectInvalid('john.test.')
124
- expectInvalid('.john.test')
125
- expectInvalid(' john.test')
126
- expectInvalid('john.test ')
127
- expectInvalid('joh-.test')
128
- expectInvalid('john.-est')
129
- expectInvalid('john.tes-')
130
- })
131
-
132
- it('throws on "dotless" TLD handles', () => {
133
- expectInvalid('org')
134
- expectInvalid('ai')
135
- expectInvalid('gg')
136
- expectInvalid('io')
137
- })
138
-
139
- it('correctly validates corner cases (modern vs. old RFCs)', () => {
140
- expectValid('12345.test')
141
- expectValid('8.cn')
142
- expectValid('4chan.org')
143
- expectValid('4chan.o-g')
144
- expectValid('blah.4chan.org')
145
- expectValid('thing.a01')
146
- expectValid('120.0.0.1.com')
147
- expectValid('0john.test')
148
- expectValid('9sta--ck.com')
149
- expectValid('99stack.com')
150
- expectValid('0ohn.test')
151
- expectValid('john.t--t')
152
- expectValid('thing.0aa.thing')
153
-
154
- expectInvalid('cn.8')
155
- expectInvalid('thing.0aa')
156
- expectInvalid('thing.0aa')
157
- })
158
-
159
- it('does not allow IP addresses as handles', () => {
160
- expectInvalid('127.0.0.1')
161
- expectInvalid('192.168.0.142')
162
- expectInvalid('fe80::7325:8a97:c100:94b')
163
- expectInvalid('2600:3c03::f03c:9100:feb0:af1f')
164
- })
165
-
166
- it('is consistent with examples from stackoverflow', () => {
167
- const okStackoverflow = [
168
- 'stack.com',
169
- 'sta-ck.com',
170
- 'sta---ck.com',
171
- 'sta--ck9.com',
172
- 'stack99.com',
173
- 'sta99ck.com',
174
- 'google.com.uk',
175
- 'google.co.in',
176
- 'google.com',
177
- 'maselkowski.pl',
178
- 'm.maselkowski.pl',
179
- 'xn--masekowski-d0b.pl',
180
- 'xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s',
181
- 'xn--stackoverflow.com',
182
- 'stackoverflow.xn--com',
183
- 'stackoverflow.co.uk',
184
- 'xn--masekowski-d0b.pl',
185
- 'xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s',
186
- ]
187
- okStackoverflow.forEach(expectValid)
188
-
189
- const badStackoverflow = [
190
- '-notvalid.at-all',
191
- '-thing.com',
192
- 'www.masełkowski.pl.com',
193
- ]
194
- badStackoverflow.forEach(expectInvalid)
195
- })
196
-
197
- it('conforms to interop valid handles', () => {
198
- const lineReader = readline.createInterface({
199
- input: fs.createReadStream(
200
- `${__dirname}/interop-files/handle_syntax_valid.txt`,
201
- ),
202
- terminal: false,
203
- })
204
- lineReader.on('line', (line) => {
205
- if (line.startsWith('#') || line.length === 0) {
206
- return
207
- }
208
- expectValid(line)
209
- })
210
- })
211
-
212
- it('conforms to interop invalid handles', () => {
213
- const lineReader = readline.createInterface({
214
- input: fs.createReadStream(
215
- `${__dirname}/interop-files/handle_syntax_invalid.txt`,
216
- ),
217
- terminal: false,
218
- })
219
- lineReader.on('line', (line) => {
220
- if (line.startsWith('#') || line.length === 0) {
221
- return
222
- }
223
- expectInvalid(line)
224
- })
225
- })
226
- })
227
-
228
- describe('normalization', () => {
229
- it('normalizes handles', () => {
230
- const normalized = normalizeAndEnsureValidHandle('JoHn.TeST')
231
- expect(normalized).toBe('john.test')
232
- })
233
-
234
- it('throws on invalid normalized handles', () => {
235
- expect(() => normalizeAndEnsureValidHandle('JoH!n.TeST')).toThrow(
236
- InvalidHandleError,
237
- )
238
- })
239
- })