@atproto/syntax 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/LICENSE.txt +1 -1
- package/dist/at-identifier.d.ts +1 -0
- package/dist/at-identifier.d.ts.map +1 -1
- package/dist/at-identifier.js +9 -0
- package/dist/at-identifier.js.map +1 -1
- package/dist/aturi.d.ts +8 -0
- package/dist/aturi.d.ts.map +1 -1
- package/dist/aturi.js +31 -40
- package/dist/aturi.js.map +1 -1
- package/dist/aturi_validation.d.ts +3 -2
- package/dist/aturi_validation.d.ts.map +1 -1
- package/dist/aturi_validation.js +13 -3
- package/dist/aturi_validation.js.map +1 -1
- package/dist/datetime.d.ts +128 -11
- package/dist/datetime.d.ts.map +1 -1
- package/dist/datetime.js +205 -79
- package/dist/datetime.js.map +1 -1
- package/dist/did.d.ts +3 -2
- package/dist/did.d.ts.map +1 -1
- package/dist/did.js +18 -13
- package/dist/did.js.map +1 -1
- package/dist/handle.d.ts +4 -3
- package/dist/handle.d.ts.map +1 -1
- package/dist/handle.js +9 -9
- package/dist/handle.js.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -22
- package/dist/index.js.map +1 -1
- package/dist/language.d.ts +18 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +30 -0
- package/dist/language.js.map +1 -0
- package/dist/nsid.d.ts +4 -4
- package/dist/nsid.d.ts.map +1 -1
- package/dist/nsid.js +9 -11
- package/dist/nsid.js.map +1 -1
- package/dist/recordkey.d.ts +2 -2
- package/dist/recordkey.d.ts.map +1 -1
- package/dist/recordkey.js +10 -10
- package/dist/recordkey.js.map +1 -1
- package/dist/tid.d.ts +2 -2
- package/dist/tid.d.ts.map +1 -1
- package/dist/tid.js +5 -5
- package/dist/tid.js.map +1 -1
- package/dist/uri.d.ts +3 -0
- package/dist/uri.d.ts.map +1 -0
- package/dist/uri.js +7 -0
- package/dist/uri.js.map +1 -0
- package/package.json +7 -4
- package/src/at-identifier.ts +12 -1
- package/src/aturi.ts +30 -1
- package/src/aturi_validation.ts +20 -4
- package/src/datetime.ts +271 -92
- package/src/did.ts +25 -15
- package/src/handle.ts +17 -13
- package/src/index.ts +7 -5
- package/src/language.ts +39 -0
- package/src/nsid.ts +13 -7
- package/src/recordkey.ts +14 -12
- package/src/tid.ts +7 -5
- package/src/uri.ts +5 -0
- package/tests/aturi.test.ts +50 -2
- package/tests/datetime.test.ts +148 -61
- package/tests/did.test.ts +1 -0
- package/tests/handle.test.ts +1 -0
- package/tests/language.test.ts +88 -0
- package/tests/nsid.test.ts +1 -0
- package/tests/recordkey.test.ts +1 -0
- package/tests/tid.test.ts +1 -0
- package/tsconfig.build.json +5 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.json +6 -4
- package/vitest.config.ts +5 -0
- package/jest.config.js +0 -7
- package/tsconfig.tests.tsbuildinfo +0 -1
package/src/recordkey.ts
CHANGED
|
@@ -17,32 +17,34 @@ const RECORD_KEY_REGEX = /^[a-zA-Z0-9_~.:-]{1,512}$/
|
|
|
17
17
|
// RFC-3986, section 3.3). The above constraints satisfy this condition, by
|
|
18
18
|
// matching the "unreserved" characters allowed in generic URI paths.
|
|
19
19
|
|
|
20
|
-
export function ensureValidRecordKey(
|
|
21
|
-
|
|
22
|
-
): asserts
|
|
20
|
+
export function ensureValidRecordKey<I extends string>(
|
|
21
|
+
input: I,
|
|
22
|
+
): asserts input is I & RecordKeyString {
|
|
23
23
|
if (
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
input.length > RECORD_KEY_MAX_LENGTH ||
|
|
25
|
+
input.length < RECORD_KEY_MIN_LENGTH
|
|
26
26
|
) {
|
|
27
27
|
throw new InvalidRecordKeyError(
|
|
28
28
|
`record key must be ${RECORD_KEY_MIN_LENGTH} to ${RECORD_KEY_MAX_LENGTH} characters`,
|
|
29
29
|
)
|
|
30
30
|
}
|
|
31
|
-
if (RECORD_KEY_INVALID_VALUES.has(
|
|
31
|
+
if (RECORD_KEY_INVALID_VALUES.has(input)) {
|
|
32
32
|
throw new InvalidRecordKeyError('record key can not be "." or ".."')
|
|
33
33
|
}
|
|
34
34
|
// simple regex to enforce most constraints via just regex and length.
|
|
35
|
-
if (!RECORD_KEY_REGEX.test(
|
|
35
|
+
if (!RECORD_KEY_REGEX.test(input)) {
|
|
36
36
|
throw new InvalidRecordKeyError('record key syntax not valid (regex)')
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export function isValidRecordKey
|
|
40
|
+
export function isValidRecordKey<I extends string>(
|
|
41
|
+
input: I,
|
|
42
|
+
): input is I & RecordKeyString {
|
|
41
43
|
return (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
RECORD_KEY_REGEX.test(
|
|
45
|
-
!RECORD_KEY_INVALID_VALUES.has(
|
|
44
|
+
input.length >= RECORD_KEY_MIN_LENGTH &&
|
|
45
|
+
input.length <= RECORD_KEY_MAX_LENGTH &&
|
|
46
|
+
RECORD_KEY_REGEX.test(input) &&
|
|
47
|
+
!RECORD_KEY_INVALID_VALUES.has(input)
|
|
46
48
|
)
|
|
47
49
|
}
|
|
48
50
|
|
package/src/tid.ts
CHANGED
|
@@ -3,18 +3,20 @@ export type TidString = string
|
|
|
3
3
|
const TID_LENGTH = 13
|
|
4
4
|
const TID_REGEX = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/
|
|
5
5
|
|
|
6
|
-
export function ensureValidTid
|
|
7
|
-
|
|
6
|
+
export function ensureValidTid<I extends string>(
|
|
7
|
+
input: I,
|
|
8
|
+
): asserts input is I & TidString {
|
|
9
|
+
if (input.length !== TID_LENGTH) {
|
|
8
10
|
throw new InvalidTidError(`TID must be ${TID_LENGTH} characters`)
|
|
9
11
|
}
|
|
10
12
|
// simple regex to enforce most constraints via just regex and length.
|
|
11
|
-
if (!TID_REGEX.test(
|
|
13
|
+
if (!TID_REGEX.test(input)) {
|
|
12
14
|
throw new InvalidTidError('TID syntax not valid (regex)')
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
export function isValidTid(
|
|
17
|
-
return
|
|
18
|
+
export function isValidTid<I extends string>(input: I): input is I & TidString {
|
|
19
|
+
return input.length === TID_LENGTH && TID_REGEX.test(input)
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export class InvalidTidError extends Error {}
|
package/src/uri.ts
ADDED
package/tests/aturi.test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from 'node:fs'
|
|
2
2
|
import * as readline from 'node:readline'
|
|
3
|
-
import {
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
import { AtUri, ensureValidAtUri, ensureValidAtUriRegex } from '../src'
|
|
4
5
|
|
|
5
|
-
describe(
|
|
6
|
+
describe(AtUri, () => {
|
|
6
7
|
it('parses valid at uris', () => {
|
|
7
8
|
// input host path query hash
|
|
8
9
|
type AtUriTest = [string, string, string, string, string]
|
|
@@ -521,5 +522,52 @@ describe('AtUri validation', () => {
|
|
|
521
522
|
})
|
|
522
523
|
})
|
|
523
524
|
|
|
525
|
+
it('properly checks that the did property is a valid did', () => {
|
|
526
|
+
const urip = new AtUri('at://did:example:123')
|
|
527
|
+
expect(urip.did).toBe('did:example:123')
|
|
528
|
+
urip.host = 'did:example:456'
|
|
529
|
+
expect(urip.did).toBe('did:example:456')
|
|
530
|
+
urip.host = 'foo.com'
|
|
531
|
+
expect(() => urip.did).toThrow()
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
it('properly checks that the collection is a valid nsid', () => {
|
|
535
|
+
const urip = new AtUri('at://foo.com')
|
|
536
|
+
expect(urip.collection).toBe('')
|
|
537
|
+
expect(() => urip.collectionSafe).toThrow()
|
|
538
|
+
|
|
539
|
+
urip.collection = 'com.example.foo'
|
|
540
|
+
expect(urip.collection).toBe('com.example.foo')
|
|
541
|
+
expect(urip.collectionSafe).toBe('com.example.foo')
|
|
542
|
+
|
|
543
|
+
urip.collection = 'com.other.foo'
|
|
544
|
+
expect(urip.collection).toBe('com.other.foo')
|
|
545
|
+
expect(urip.collectionSafe).toBe('com.other.foo')
|
|
546
|
+
|
|
547
|
+
expect(() => (urip.collection = 'not a valid nsid')).toThrow()
|
|
548
|
+
expect(urip.collection).toBe('com.other.foo') // unchanged after failed set
|
|
549
|
+
|
|
550
|
+
urip.unsafelySetCollection('not-a-valid-nsid')
|
|
551
|
+
expect(urip.collection).toBe('not-a-valid-nsid')
|
|
552
|
+
expect(() => urip.collectionSafe).toThrow()
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('properly checks that the rkey is a valid record key', () => {
|
|
556
|
+
const urip = new AtUri('at://foo.com')
|
|
557
|
+
expect(urip.rkey).toBe('')
|
|
558
|
+
expect(() => urip.rkeySafe).toThrow()
|
|
559
|
+
|
|
560
|
+
urip.rkey = 'valid_rkey-123'
|
|
561
|
+
expect(urip.rkey).toBe('valid_rkey-123')
|
|
562
|
+
expect(urip.rkeySafe).toBe('valid_rkey-123')
|
|
563
|
+
|
|
564
|
+
expect(() => (urip.rkey = 'not a valid rkey')).toThrow()
|
|
565
|
+
expect(urip.rkey).toBe('valid_rkey-123') // unchanged after failed set
|
|
566
|
+
|
|
567
|
+
urip.unsafelySetRkey('not a valid rkey')
|
|
568
|
+
expect(urip.rkey).toBe('not a valid rkey')
|
|
569
|
+
expect(() => urip.rkeySafe).toThrow()
|
|
570
|
+
})
|
|
571
|
+
|
|
524
572
|
// NOTE: this package is currently more permissive than spec about AT URIs, so invalid cases are not errors
|
|
525
573
|
})
|
package/tests/datetime.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fs from 'node:fs'
|
|
2
|
-
import
|
|
2
|
+
import { describe, expect, it, test } from 'vitest'
|
|
3
3
|
import {
|
|
4
4
|
InvalidDatetimeError,
|
|
5
5
|
ensureValidDatetime,
|
|
@@ -8,67 +8,111 @@ import {
|
|
|
8
8
|
normalizeDatetimeAlways,
|
|
9
9
|
} from '../src'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
11
|
+
const interopValid = readLines(
|
|
12
|
+
`${__dirname}/interop-files/datetime_syntax_valid.txt`,
|
|
13
|
+
)
|
|
14
|
+
const interopInvalidSyntax = readLines(
|
|
15
|
+
`${__dirname}/interop-files/datetime_syntax_invalid.txt`,
|
|
16
|
+
)
|
|
17
|
+
const interopInvalidParse = readLines(
|
|
18
|
+
`${__dirname}/interop-files/datetime_parse_invalid.txt`,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
describe(ensureValidDatetime, () => {
|
|
22
|
+
describe('valid interop', () => {
|
|
23
|
+
for (const dt of interopValid) {
|
|
24
|
+
test(dt, () => {
|
|
25
|
+
expect(() => ensureValidDatetime(dt)).not.toThrow()
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('fails on interop (invalid syntax)', () => {
|
|
31
|
+
for (const dt of interopInvalidSyntax) {
|
|
32
|
+
test(dt, () => {
|
|
33
|
+
expect(() => ensureValidDatetime(dt)).toThrow(InvalidDatetimeError)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('fails on interop (invalid parse)', () => {
|
|
39
|
+
for (const dt of interopInvalidParse) {
|
|
40
|
+
test(dt, () => {
|
|
41
|
+
expect(() => ensureValidDatetime(dt)).toThrow(InvalidDatetimeError)
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('rejects datetime that normalizes past year 9999 due to negative offset', () => {
|
|
47
|
+
// 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
|
|
48
|
+
// UTC advances it to 10000-01-01T00:00:00Z, which is out of range
|
|
49
|
+
expect(() => ensureValidDatetime('9999-12-31T23:59:00-00:01')).toThrow(
|
|
50
|
+
InvalidDatetimeError,
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe(isValidDatetime, () => {
|
|
56
|
+
describe('valid interop', () => {
|
|
57
|
+
for (const dt of interopValid) {
|
|
58
|
+
test(dt, () => {
|
|
59
|
+
expect(isValidDatetime(dt)).toBe(true)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('fails on interop (invalid syntax)', () => {
|
|
65
|
+
for (const dt of interopInvalidSyntax) {
|
|
66
|
+
test(dt, () => {
|
|
67
|
+
expect(isValidDatetime(dt)).toBe(false)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('fails on interop (invalid parse)', () => {
|
|
73
|
+
for (const dt of interopInvalidParse) {
|
|
74
|
+
test(dt, () => {
|
|
75
|
+
expect(isValidDatetime(dt)).toBe(false)
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('rejects datetime that normalizes past year 9999 due to negative offset', () => {
|
|
81
|
+
// 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
|
|
82
|
+
// UTC advances it to 10000-01-01T00:00:00Z, which is out of range
|
|
83
|
+
expect(isValidDatetime('9999-12-31T23:59:00-00:01')).toBe(false)
|
|
67
84
|
})
|
|
68
85
|
})
|
|
69
86
|
|
|
70
|
-
describe(
|
|
71
|
-
|
|
87
|
+
describe(normalizeDatetime, () => {
|
|
88
|
+
describe('valid interop', () => {
|
|
89
|
+
for (const dt of interopValid) {
|
|
90
|
+
test(dt, () => {
|
|
91
|
+
expect(() => normalizeDatetime(dt)).not.toThrow()
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// @NOTE Normalize will actually succeed on some of the invalid syntax cases,
|
|
97
|
+
// because it is more lenient than the regex validation.
|
|
98
|
+
|
|
99
|
+
// describe('fails on interop (invalid syntax)', () => {
|
|
100
|
+
// for (const dt of interopInvalidSyntax) {
|
|
101
|
+
// test(dt, () => {
|
|
102
|
+
// expect(() => normalizeDatetime(dt)).toThrow(InvalidDatetimeError)
|
|
103
|
+
// })
|
|
104
|
+
// }
|
|
105
|
+
// })
|
|
106
|
+
|
|
107
|
+
describe('fails on interop (invalid parse)', () => {
|
|
108
|
+
for (const dt of interopInvalidParse) {
|
|
109
|
+
test(dt, () => {
|
|
110
|
+
expect(() => normalizeDatetime(dt)).toThrow(InvalidDatetimeError)
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('normalizes valid input', () => {
|
|
72
116
|
expect(normalizeDatetime('1234-04-12T23:20:50Z')).toEqual(
|
|
73
117
|
'1234-04-12T23:20:50.000Z',
|
|
74
118
|
)
|
|
@@ -89,7 +133,7 @@ describe('normalization', () => {
|
|
|
89
133
|
)
|
|
90
134
|
})
|
|
91
135
|
|
|
92
|
-
it('throws on invalid
|
|
136
|
+
it('throws on invalid input', () => {
|
|
93
137
|
expect(() => normalizeDatetime('')).toThrow(InvalidDatetimeError)
|
|
94
138
|
expect(() => normalizeDatetime('blah')).toThrow(InvalidDatetimeError)
|
|
95
139
|
expect(() => normalizeDatetime('1999-19-39T23:20:50.123Z')).toThrow(
|
|
@@ -104,15 +148,58 @@ describe('normalization', () => {
|
|
|
104
148
|
expect(() => normalizeDatetime('0001-01-01T00:00:00+01:00')).toThrow(
|
|
105
149
|
InvalidDatetimeError,
|
|
106
150
|
)
|
|
151
|
+
// 9999-12-31T23:59:00-00:01 is syntactically valid, but normalizing to
|
|
152
|
+
// UTC advances it to 10000-01-01T00:00:00Z, which is out of range
|
|
153
|
+
expect(() => normalizeDatetime('9999-12-31T23:59:00-00:01')).toThrow(
|
|
154
|
+
InvalidDatetimeError,
|
|
155
|
+
)
|
|
107
156
|
})
|
|
157
|
+
})
|
|
108
158
|
|
|
109
|
-
|
|
159
|
+
describe(normalizeDatetimeAlways, () => {
|
|
160
|
+
it('normalizes valid input', () => {
|
|
110
161
|
expect(normalizeDatetimeAlways('1985-04-12T23:20:50Z')).toEqual(
|
|
111
162
|
'1985-04-12T23:20:50.000Z',
|
|
112
163
|
)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('normalizes invalid input', () => {
|
|
113
167
|
expect(normalizeDatetimeAlways('blah')).toEqual('1970-01-01T00:00:00.000Z')
|
|
114
168
|
expect(normalizeDatetimeAlways('0000-01-01T00:00:00+01:00')).toEqual(
|
|
115
169
|
'1970-01-01T00:00:00.000Z',
|
|
116
170
|
)
|
|
117
171
|
})
|
|
172
|
+
|
|
173
|
+
describe('valid interop', () => {
|
|
174
|
+
for (const dt of interopValid) {
|
|
175
|
+
test(dt, () => {
|
|
176
|
+
// @NOTE we can't test the returned value as some will normalize while others won't.
|
|
177
|
+
expect(() => normalizeDatetimeAlways(dt)).not.toThrow()
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('succeeds on interop (invalid syntax)', () => {
|
|
183
|
+
for (const dt of interopInvalidSyntax) {
|
|
184
|
+
test(dt, () => {
|
|
185
|
+
// @NOTE we can't test the returned value as some will normalize while others won't.
|
|
186
|
+
expect(() => normalizeDatetimeAlways(dt)).not.toThrow()
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
describe('succeeds on interop invalid parse', () => {
|
|
192
|
+
for (const dt of interopInvalidParse) {
|
|
193
|
+
test(dt, () => {
|
|
194
|
+
expect(normalizeDatetimeAlways(dt)).toEqual('1970-01-01T00:00:00.000Z')
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
})
|
|
118
198
|
})
|
|
199
|
+
|
|
200
|
+
function readLines(filePath: string): string[] {
|
|
201
|
+
return fs
|
|
202
|
+
.readFileSync(filePath, 'utf-8')
|
|
203
|
+
.split(/\r?\n/)
|
|
204
|
+
.filter((line) => !line.startsWith('#') && line.length > 0)
|
|
205
|
+
}
|
package/tests/did.test.ts
CHANGED
package/tests/handle.test.ts
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { isValidLanguage, parseLanguageString } from '../src'
|
|
3
|
+
|
|
4
|
+
describe(isValidLanguage, () => {
|
|
5
|
+
it('validates BCP 47', () => {
|
|
6
|
+
// valid
|
|
7
|
+
expect(isValidLanguage('de')).toEqual(true)
|
|
8
|
+
expect(isValidLanguage('de-CH')).toEqual(true)
|
|
9
|
+
expect(isValidLanguage('de-DE-1901')).toEqual(true)
|
|
10
|
+
expect(isValidLanguage('es-419')).toEqual(true)
|
|
11
|
+
expect(isValidLanguage('sl-IT-nedis')).toEqual(true)
|
|
12
|
+
expect(isValidLanguage('mn-Cyrl-MN')).toEqual(true)
|
|
13
|
+
expect(isValidLanguage('x-fr-CH')).toEqual(true)
|
|
14
|
+
expect(
|
|
15
|
+
isValidLanguage('en-GB-boont-r-extended-sequence-x-private'),
|
|
16
|
+
).toEqual(true)
|
|
17
|
+
expect(isValidLanguage('sr-Cyrl')).toEqual(true)
|
|
18
|
+
expect(isValidLanguage('hy-Latn-IT-arevela')).toEqual(true)
|
|
19
|
+
expect(isValidLanguage('i-klingon')).toEqual(true)
|
|
20
|
+
// invalid
|
|
21
|
+
expect(isValidLanguage('')).toEqual(false)
|
|
22
|
+
expect(isValidLanguage('x')).toEqual(false)
|
|
23
|
+
expect(isValidLanguage('de-CH-')).toEqual(false)
|
|
24
|
+
expect(isValidLanguage('i-bad-grandfathered')).toEqual(false)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe(parseLanguageString, () => {
|
|
29
|
+
it('parses BCP 47', () => {
|
|
30
|
+
// valid
|
|
31
|
+
expect(parseLanguageString('de')).toEqual({
|
|
32
|
+
language: 'de',
|
|
33
|
+
})
|
|
34
|
+
expect(parseLanguageString('de-CH')).toEqual({
|
|
35
|
+
language: 'de',
|
|
36
|
+
region: 'CH',
|
|
37
|
+
})
|
|
38
|
+
expect(parseLanguageString('de-DE-1901')).toEqual({
|
|
39
|
+
language: 'de',
|
|
40
|
+
region: 'DE',
|
|
41
|
+
variant: '1901',
|
|
42
|
+
})
|
|
43
|
+
expect(parseLanguageString('es-419')).toEqual({
|
|
44
|
+
language: 'es',
|
|
45
|
+
region: '419',
|
|
46
|
+
})
|
|
47
|
+
expect(parseLanguageString('sl-IT-nedis')).toEqual({
|
|
48
|
+
language: 'sl',
|
|
49
|
+
region: 'IT',
|
|
50
|
+
variant: 'nedis',
|
|
51
|
+
})
|
|
52
|
+
expect(parseLanguageString('mn-Cyrl-MN')).toEqual({
|
|
53
|
+
language: 'mn',
|
|
54
|
+
script: 'Cyrl',
|
|
55
|
+
region: 'MN',
|
|
56
|
+
})
|
|
57
|
+
expect(parseLanguageString('x-fr-CH')).toEqual({
|
|
58
|
+
privateUse: 'x-fr-CH',
|
|
59
|
+
})
|
|
60
|
+
expect(
|
|
61
|
+
parseLanguageString('en-GB-boont-r-extended-sequence-x-private'),
|
|
62
|
+
).toEqual({
|
|
63
|
+
language: 'en',
|
|
64
|
+
region: 'GB',
|
|
65
|
+
variant: 'boont',
|
|
66
|
+
extension: 'r-extended-sequence',
|
|
67
|
+
privateUse: 'x-private',
|
|
68
|
+
})
|
|
69
|
+
expect(parseLanguageString('sr-Cyrl')).toEqual({
|
|
70
|
+
language: 'sr',
|
|
71
|
+
script: 'Cyrl',
|
|
72
|
+
})
|
|
73
|
+
expect(parseLanguageString('hy-Latn-IT-arevela')).toEqual({
|
|
74
|
+
language: 'hy',
|
|
75
|
+
script: 'Latn',
|
|
76
|
+
region: 'IT',
|
|
77
|
+
variant: 'arevela',
|
|
78
|
+
})
|
|
79
|
+
expect(parseLanguageString('i-klingon')).toEqual({
|
|
80
|
+
grandfathered: 'i-klingon',
|
|
81
|
+
})
|
|
82
|
+
// invalid
|
|
83
|
+
expect(parseLanguageString('')).toEqual(null)
|
|
84
|
+
expect(parseLanguageString('x')).toEqual(null)
|
|
85
|
+
expect(parseLanguageString('de-CH-')).toEqual(null)
|
|
86
|
+
expect(parseLanguageString('i-bad-grandfathered')).toEqual(null)
|
|
87
|
+
})
|
|
88
|
+
})
|
package/tests/nsid.test.ts
CHANGED
package/tests/recordkey.test.ts
CHANGED
package/tests/tid.test.ts
CHANGED
package/tsconfig.build.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../../tsconfig/isomorphic.json",
|
|
3
|
+
"include": ["./src"],
|
|
4
|
+
"exclude": ["**/*.test.ts"],
|
|
3
5
|
"compilerOptions": {
|
|
4
6
|
"noImplicitAny": true,
|
|
7
|
+
"importHelpers": true,
|
|
8
|
+
"target": "ES2023",
|
|
5
9
|
"rootDir": "./src",
|
|
6
10
|
"outDir": "./dist"
|
|
7
|
-
}
|
|
8
|
-
"include": ["./src"]
|
|
11
|
+
}
|
|
9
12
|
}
|
|
@@ -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/nsid.ts","./src/recordkey.ts","./src/tid.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"],"version":"5.8.2"}
|
package/tsconfig.tests.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "../../tsconfig/
|
|
2
|
+
"extends": "../../tsconfig/vitest.json",
|
|
3
|
+
"include": ["./tests", "./src/**/*.test.ts"],
|
|
3
4
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
"noImplicitAny": true,
|
|
6
|
+
"rootDir": "./",
|
|
7
|
+
"baseUrl": "./"
|
|
8
|
+
}
|
|
7
9
|
}
|
package/vitest.config.ts
ADDED
package/jest.config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["./tests/aturi.test.ts","./tests/datetime.test.ts","./tests/did.test.ts","./tests/handle.test.ts","./tests/nsid.test.ts","./tests/recordkey.test.ts","./tests/tid.test.ts"],"version":"5.8.3"}
|