@atproto/lex-schema 0.0.8 → 0.0.10

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 (279) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE.txt +1 -1
  3. package/dist/core/$type.d.ts +11 -0
  4. package/dist/core/$type.d.ts.map +1 -1
  5. package/dist/core/$type.js +4 -0
  6. package/dist/core/$type.js.map +1 -1
  7. package/dist/core/schema.d.ts +31 -24
  8. package/dist/core/schema.d.ts.map +1 -1
  9. package/dist/core/schema.js +38 -8
  10. package/dist/core/schema.js.map +1 -1
  11. package/dist/core/string-format.d.ts +35 -35
  12. package/dist/core/string-format.d.ts.map +1 -1
  13. package/dist/core/string-format.js +49 -91
  14. package/dist/core/string-format.js.map +1 -1
  15. package/dist/core/validation-issue.js +1 -1
  16. package/dist/core/validation-issue.js.map +1 -1
  17. package/dist/core/validator.d.ts +53 -32
  18. package/dist/core/validator.d.ts.map +1 -1
  19. package/dist/core/validator.js +18 -22
  20. package/dist/core/validator.js.map +1 -1
  21. package/dist/external.d.ts +0 -85
  22. package/dist/external.d.ts.map +1 -1
  23. package/dist/external.js +0 -164
  24. package/dist/external.js.map +1 -1
  25. package/dist/helpers.d.ts +10 -5
  26. package/dist/helpers.d.ts.map +1 -1
  27. package/dist/helpers.js +3 -3
  28. package/dist/helpers.js.map +1 -1
  29. package/dist/schema/array.d.ts +9 -5
  30. package/dist/schema/array.d.ts.map +1 -1
  31. package/dist/schema/array.js +14 -5
  32. package/dist/schema/array.js.map +1 -1
  33. package/dist/schema/blob.d.ts +9 -7
  34. package/dist/schema/blob.d.ts.map +1 -1
  35. package/dist/schema/blob.js +9 -5
  36. package/dist/schema/blob.js.map +1 -1
  37. package/dist/schema/boolean.d.ts +3 -7
  38. package/dist/schema/boolean.d.ts.map +1 -1
  39. package/dist/schema/boolean.js +6 -7
  40. package/dist/schema/boolean.js.map +1 -1
  41. package/dist/schema/bytes.d.ts +3 -2
  42. package/dist/schema/bytes.d.ts.map +1 -1
  43. package/dist/schema/bytes.js +7 -3
  44. package/dist/schema/bytes.js.map +1 -1
  45. package/dist/schema/cid.d.ts +10 -8
  46. package/dist/schema/cid.d.ts.map +1 -1
  47. package/dist/schema/cid.js +5 -1
  48. package/dist/schema/cid.js.map +1 -1
  49. package/dist/schema/custom.d.ts +6 -5
  50. package/dist/schema/custom.d.ts.map +1 -1
  51. package/dist/schema/custom.js +10 -4
  52. package/dist/schema/custom.js.map +1 -1
  53. package/dist/schema/dict.d.ts +8 -8
  54. package/dist/schema/dict.d.ts.map +1 -1
  55. package/dist/schema/dict.js +11 -2
  56. package/dist/schema/dict.js.map +1 -1
  57. package/dist/schema/discriminated-union.d.ts +21 -14
  58. package/dist/schema/discriminated-union.d.ts.map +1 -1
  59. package/dist/schema/discriminated-union.js +7 -0
  60. package/dist/schema/discriminated-union.js.map +1 -1
  61. package/dist/schema/enum.d.ts +7 -9
  62. package/dist/schema/enum.d.ts.map +1 -1
  63. package/dist/schema/enum.js +8 -4
  64. package/dist/schema/enum.js.map +1 -1
  65. package/dist/schema/integer.d.ts +5 -5
  66. package/dist/schema/integer.d.ts.map +1 -1
  67. package/dist/schema/integer.js +9 -5
  68. package/dist/schema/integer.js.map +1 -1
  69. package/dist/schema/intersection.d.ts +4 -4
  70. package/dist/schema/intersection.d.ts.map +1 -1
  71. package/dist/schema/intersection.js +5 -0
  72. package/dist/schema/intersection.js.map +1 -1
  73. package/dist/schema/literal.d.ts +6 -9
  74. package/dist/schema/literal.d.ts.map +1 -1
  75. package/dist/schema/literal.js +7 -4
  76. package/dist/schema/literal.js.map +1 -1
  77. package/dist/schema/never.d.ts +3 -2
  78. package/dist/schema/never.d.ts.map +1 -1
  79. package/dist/schema/never.js +5 -1
  80. package/dist/schema/never.js.map +1 -1
  81. package/dist/schema/null.d.ts +4 -3
  82. package/dist/schema/null.d.ts.map +1 -1
  83. package/dist/schema/null.js +6 -4
  84. package/dist/schema/null.js.map +1 -1
  85. package/dist/schema/nullable.d.ts +6 -5
  86. package/dist/schema/nullable.d.ts.map +1 -1
  87. package/dist/schema/nullable.js +9 -5
  88. package/dist/schema/nullable.js.map +1 -1
  89. package/dist/schema/object.d.ts +10 -8
  90. package/dist/schema/object.d.ts.map +1 -1
  91. package/dist/schema/object.js +11 -3
  92. package/dist/schema/object.js.map +1 -1
  93. package/dist/schema/optional.d.ts +7 -5
  94. package/dist/schema/optional.d.ts.map +1 -1
  95. package/dist/schema/optional.js +14 -6
  96. package/dist/schema/optional.js.map +1 -1
  97. package/dist/schema/params.d.ts +24 -13
  98. package/dist/schema/params.d.ts.map +1 -1
  99. package/dist/schema/params.js +47 -25
  100. package/dist/schema/params.js.map +1 -1
  101. package/dist/schema/payload.d.ts +12 -9
  102. package/dist/schema/payload.d.ts.map +1 -1
  103. package/dist/schema/payload.js +11 -0
  104. package/dist/schema/payload.js.map +1 -1
  105. package/dist/schema/permission-set.d.ts +1 -0
  106. package/dist/schema/permission-set.d.ts.map +1 -1
  107. package/dist/schema/permission-set.js +5 -0
  108. package/dist/schema/permission-set.js.map +1 -1
  109. package/dist/schema/permission.d.ts +6 -5
  110. package/dist/schema/permission.d.ts.map +1 -1
  111. package/dist/schema/permission.js +5 -0
  112. package/dist/schema/permission.js.map +1 -1
  113. package/dist/schema/procedure.d.ts +2 -1
  114. package/dist/schema/procedure.d.ts.map +1 -1
  115. package/dist/schema/procedure.js +5 -0
  116. package/dist/schema/procedure.js.map +1 -1
  117. package/dist/schema/query.d.ts +2 -1
  118. package/dist/schema/query.d.ts.map +1 -1
  119. package/dist/schema/query.js +5 -0
  120. package/dist/schema/query.js.map +1 -1
  121. package/dist/schema/record.d.ts +48 -30
  122. package/dist/schema/record.d.ts.map +1 -1
  123. package/dist/schema/record.js +12 -9
  124. package/dist/schema/record.js.map +1 -1
  125. package/dist/schema/ref.d.ts +9 -6
  126. package/dist/schema/ref.d.ts.map +1 -1
  127. package/dist/schema/ref.js +9 -16
  128. package/dist/schema/ref.js.map +1 -1
  129. package/dist/schema/refine.d.ts +4 -4
  130. package/dist/schema/refine.d.ts.map +1 -1
  131. package/dist/schema/refine.js.map +1 -1
  132. package/dist/schema/regexp.d.ts +4 -3
  133. package/dist/schema/regexp.d.ts.map +1 -1
  134. package/dist/schema/regexp.js +5 -0
  135. package/dist/schema/regexp.js.map +1 -1
  136. package/dist/schema/string.d.ts +7 -8
  137. package/dist/schema/string.d.ts.map +1 -1
  138. package/dist/schema/string.js +13 -19
  139. package/dist/schema/string.js.map +1 -1
  140. package/dist/schema/subscription.d.ts +2 -1
  141. package/dist/schema/subscription.d.ts.map +1 -1
  142. package/dist/schema/subscription.js +5 -0
  143. package/dist/schema/subscription.js.map +1 -1
  144. package/dist/schema/token.d.ts +6 -5
  145. package/dist/schema/token.d.ts.map +1 -1
  146. package/dist/schema/token.js +5 -0
  147. package/dist/schema/token.js.map +1 -1
  148. package/dist/schema/typed-object.d.ts +43 -26
  149. package/dist/schema/typed-object.d.ts.map +1 -1
  150. package/dist/schema/typed-object.js +6 -3
  151. package/dist/schema/typed-object.js.map +1 -1
  152. package/dist/schema/typed-ref.d.ts +16 -25
  153. package/dist/schema/typed-ref.d.ts.map +1 -1
  154. package/dist/schema/typed-ref.js +7 -17
  155. package/dist/schema/typed-ref.js.map +1 -1
  156. package/dist/schema/typed-union.d.ts +9 -21
  157. package/dist/schema/typed-union.d.ts.map +1 -1
  158. package/dist/schema/typed-union.js +15 -11
  159. package/dist/schema/typed-union.js.map +1 -1
  160. package/dist/schema/union.d.ts +6 -6
  161. package/dist/schema/union.d.ts.map +1 -1
  162. package/dist/schema/union.js +7 -5
  163. package/dist/schema/union.js.map +1 -1
  164. package/dist/schema/unknown-object.d.ts +5 -4
  165. package/dist/schema/unknown-object.d.ts.map +1 -1
  166. package/dist/schema/unknown-object.js +5 -1
  167. package/dist/schema/unknown-object.js.map +1 -1
  168. package/dist/schema/unknown.d.ts +3 -2
  169. package/dist/schema/unknown.d.ts.map +1 -1
  170. package/dist/schema/unknown.js +5 -1
  171. package/dist/schema/unknown.js.map +1 -1
  172. package/dist/schema/with-default.d.ts +9 -0
  173. package/dist/schema/with-default.d.ts.map +1 -0
  174. package/dist/schema/with-default.js +27 -0
  175. package/dist/schema/with-default.js.map +1 -0
  176. package/dist/schema.d.ts +2 -2
  177. package/dist/schema.d.ts.map +1 -1
  178. package/dist/schema.js +2 -4
  179. package/dist/schema.js.map +1 -1
  180. package/dist/util/assertion-util.d.ts +0 -6
  181. package/dist/util/assertion-util.d.ts.map +1 -1
  182. package/dist/util/assertion-util.js +0 -28
  183. package/dist/util/assertion-util.js.map +1 -1
  184. package/dist/util/memoize.d.ts +2 -2
  185. package/dist/util/memoize.d.ts.map +1 -1
  186. package/dist/util/memoize.js +23 -39
  187. package/dist/util/memoize.js.map +1 -1
  188. package/package.json +3 -3
  189. package/src/core/$type.test.ts +20 -0
  190. package/src/core/$type.ts +30 -0
  191. package/src/core/schema.ts +86 -38
  192. package/src/core/string-format.ts +119 -158
  193. package/src/core/validation-issue.ts +1 -1
  194. package/src/core/validator.ts +93 -53
  195. package/src/external.ts +0 -404
  196. package/src/helpers.test.ts +22 -21
  197. package/src/helpers.ts +14 -14
  198. package/src/schema/array.test.ts +38 -40
  199. package/src/schema/array.ts +35 -13
  200. package/src/schema/blob.test.ts +21 -21
  201. package/src/schema/blob.ts +19 -17
  202. package/src/schema/boolean.test.ts +9 -8
  203. package/src/schema/boolean.ts +7 -13
  204. package/src/schema/bytes.test.ts +13 -13
  205. package/src/schema/bytes.ts +13 -8
  206. package/src/schema/cid.test.ts +3 -3
  207. package/src/schema/cid.ts +15 -13
  208. package/src/schema/custom.test.ts +26 -26
  209. package/src/schema/custom.ts +20 -13
  210. package/src/schema/dict.test.ts +21 -39
  211. package/src/schema/dict.ts +28 -19
  212. package/src/schema/discriminated-union.test.ts +128 -128
  213. package/src/schema/discriminated-union.ts +45 -26
  214. package/src/schema/enum.test.ts +17 -16
  215. package/src/schema/enum.ts +16 -16
  216. package/src/schema/integer.test.ts +22 -21
  217. package/src/schema/integer.ts +12 -9
  218. package/src/schema/intersection.test.ts +10 -10
  219. package/src/schema/intersection.ts +17 -14
  220. package/src/schema/literal.test.ts +35 -34
  221. package/src/schema/literal.ts +12 -15
  222. package/src/schema/never.test.ts +5 -5
  223. package/src/schema/never.ts +7 -2
  224. package/src/schema/null.test.ts +3 -3
  225. package/src/schema/null.ts +9 -9
  226. package/src/schema/nullable.test.ts +31 -42
  227. package/src/schema/nullable.ts +17 -9
  228. package/src/schema/object.test.ts +10 -12
  229. package/src/schema/object.ts +27 -18
  230. package/src/schema/optional.test.ts +21 -28
  231. package/src/schema/optional.ts +27 -10
  232. package/src/schema/params.test.ts +471 -47
  233. package/src/schema/params.ts +72 -38
  234. package/src/schema/payload.test.ts +150 -156
  235. package/src/schema/payload.ts +35 -19
  236. package/src/schema/permission-set.test.ts +206 -273
  237. package/src/schema/permission-set.ts +8 -0
  238. package/src/schema/permission.test.ts +177 -177
  239. package/src/schema/permission.ts +13 -5
  240. package/src/schema/procedure.test.ts +183 -242
  241. package/src/schema/procedure.ts +18 -5
  242. package/src/schema/query.test.ts +186 -200
  243. package/src/schema/query.ts +16 -4
  244. package/src/schema/record.test.ts +121 -101
  245. package/src/schema/record.ts +74 -40
  246. package/src/schema/ref.test.ts +101 -118
  247. package/src/schema/ref.ts +33 -28
  248. package/src/schema/refine.test.ts +28 -28
  249. package/src/schema/refine.ts +23 -20
  250. package/src/schema/regexp.test.ts +29 -33
  251. package/src/schema/regexp.ts +11 -7
  252. package/src/schema/string.test.ts +35 -35
  253. package/src/schema/string.ts +24 -33
  254. package/src/schema/subscription.test.ts +259 -387
  255. package/src/schema/subscription.ts +16 -4
  256. package/src/schema/token.test.ts +47 -324
  257. package/src/schema/token.ts +14 -7
  258. package/src/schema/typed-object.test.ts +98 -81
  259. package/src/schema/typed-object.ts +68 -33
  260. package/src/schema/typed-ref.test.ts +206 -234
  261. package/src/schema/typed-ref.ts +40 -42
  262. package/src/schema/typed-union.test.ts +40 -64
  263. package/src/schema/typed-union.ts +36 -58
  264. package/src/schema/union.test.ts +17 -27
  265. package/src/schema/union.ts +20 -16
  266. package/src/schema/unknown-object.test.ts +8 -8
  267. package/src/schema/unknown-object.ts +9 -7
  268. package/src/schema/unknown.test.ts +4 -4
  269. package/src/schema/unknown.ts +7 -5
  270. package/src/schema/with-default.ts +35 -0
  271. package/src/schema.ts +2 -6
  272. package/src/util/assertion-util.ts +0 -39
  273. package/src/util/memoize.ts +26 -46
  274. package/dist/schema/_parameters.d.ts +0 -17
  275. package/dist/schema/_parameters.d.ts.map +0 -1
  276. package/dist/schema/_parameters.js +0 -20
  277. package/dist/schema/_parameters.js.map +0 -1
  278. package/src/schema/_parameters.test.ts +0 -417
  279. package/src/schema/_parameters.ts +0 -26
@@ -10,10 +10,12 @@ export type InferSubscriptionMessage<S extends Subscription> = Infer<
10
10
  >
11
11
 
12
12
  export class Subscription<
13
- TNsid extends NsidString = NsidString,
14
- TParameters extends ParamsSchema = ParamsSchema,
15
- TMessage extends Schema = Schema,
16
- TErrors extends undefined | readonly string[] = undefined | readonly string[],
13
+ const TNsid extends NsidString = NsidString,
14
+ const TParameters extends ParamsSchema = ParamsSchema,
15
+ const TMessage extends Schema = Schema,
16
+ const TErrors extends undefined | readonly string[] =
17
+ | undefined
18
+ | readonly string[],
17
19
  > {
18
20
  readonly type = 'subscription' as const
19
21
 
@@ -24,3 +26,13 @@ export class Subscription<
24
26
  readonly errors: TErrors,
25
27
  ) {}
26
28
  }
29
+
30
+ /*@__NO_SIDE_EFFECTS__*/
31
+ export function subscription<
32
+ const N extends NsidString,
33
+ const P extends ParamsSchema,
34
+ const M extends Schema,
35
+ const E extends undefined | readonly string[] = undefined,
36
+ >(nsid: N, parameters: P, message: M, errors: E = undefined as E) {
37
+ return new Subscription<N, P, M, E>(nsid, parameters, message, errors)
38
+ }
@@ -1,30 +1,29 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { TokenSchema } from './token.js'
2
+ import { token } from './token.js'
3
3
 
4
4
  describe('TokenSchema', () => {
5
5
  describe('basic validation', () => {
6
- const schema = new TokenSchema('mytoken')
6
+ const schema = token('my.to.ken')
7
7
 
8
8
  it('validates exact token match', () => {
9
- const result = schema.safeParse('mytoken')
10
- expect(result.success).toBe(true)
11
- if (result.success) {
12
- expect(result.value).toBe('mytoken')
13
- }
9
+ expect(schema.safeParse('my.to.ken')).toMatchObject({
10
+ success: true,
11
+ value: 'my.to.ken',
12
+ })
14
13
  })
15
14
 
16
15
  it('rejects different strings', () => {
17
- const result = schema.safeParse('othertoken')
16
+ const result = schema.safeParse('other.to.ken')
18
17
  expect(result.success).toBe(false)
19
18
  })
20
19
 
21
20
  it('rejects similar strings with different case', () => {
22
- const result = schema.safeParse('MyToken')
21
+ const result = schema.safeParse('My.To.Ken')
23
22
  expect(result.success).toBe(false)
24
23
  })
25
24
 
26
25
  it('rejects partial matches', () => {
27
- const result = schema.safeParse('my')
26
+ const result = schema.safeParse('my.to')
28
27
  expect(result.success).toBe(false)
29
28
  })
30
29
 
@@ -32,37 +31,56 @@ describe('TokenSchema', () => {
32
31
  const result = schema.safeParse('')
33
32
  expect(result.success).toBe(false)
34
33
  })
34
+
35
+ it('rejects symbols', () => {
36
+ const result = schema.safeParse(Symbol.for(schema.toString()))
37
+ expect(result.success).toBe(false)
38
+ })
39
+
40
+ it('rejects functions', () => {
41
+ const result = schema.safeParse(() => schema)
42
+ expect(result.success).toBe(false)
43
+ })
44
+
45
+ it('rejects dates', () => {
46
+ const result = schema.safeParse(new Date())
47
+ expect(result.success).toBe(false)
48
+ })
49
+
50
+ it('rejects regular expressions', () => {
51
+ const result = schema.safeParse(/mytoken/)
52
+ expect(result.success).toBe(false)
53
+ })
35
54
  })
36
55
 
37
56
  describe('TokenSchema instance validation', () => {
38
- const schema = new TokenSchema('mytoken')
57
+ const schema = token('my.to.ken')
39
58
 
40
59
  it('accepts TokenSchema instance with same value', () => {
41
- const otherInstance = new TokenSchema('mytoken')
60
+ const otherInstance = token('my.to.ken')
42
61
  const result = schema.safeParse(otherInstance)
43
62
  expect(result.success).toBe(true)
44
63
  if (result.success) {
45
- expect(result.value).toBe('mytoken')
64
+ expect(result.value).toBe('my.to.ken')
46
65
  }
47
66
  })
48
67
 
49
68
  it('rejects TokenSchema instance with different value', () => {
50
- const otherInstance = new TokenSchema('othertoken')
69
+ const otherInstance = token('other.to.ken')
51
70
  const result = schema.safeParse(otherInstance)
52
71
  expect(result.success).toBe(false)
53
72
  })
54
73
 
55
74
  it('accepts itself as input', () => {
56
- const result = schema.safeParse(schema)
57
- expect(result.success).toBe(true)
58
- if (result.success) {
59
- expect(result.value).toBe('mytoken')
60
- }
75
+ expect(schema.safeParse(schema)).toMatchObject({
76
+ success: true,
77
+ value: 'my.to.ken',
78
+ })
61
79
  })
62
80
  })
63
81
 
64
82
  describe('type validation', () => {
65
- const schema = new TokenSchema('mytoken')
83
+ const schema = token('my.to.ken')
66
84
 
67
85
  it('rejects null', () => {
68
86
  const result = schema.safeParse(null)
@@ -100,330 +118,35 @@ describe('TokenSchema', () => {
100
118
  })
101
119
  })
102
120
 
103
- describe('special token values', () => {
104
- it('validates token with spaces', () => {
105
- const schema = new TokenSchema('my token')
106
- expect(schema.safeParse('my token').success).toBe(true)
107
- })
108
-
109
- it('validates token with special characters', () => {
110
- const schema = new TokenSchema('token-with-dashes')
111
- expect(schema.safeParse('token-with-dashes').success).toBe(true)
112
- })
113
-
114
- it('validates token with underscores', () => {
115
- const schema = new TokenSchema('token_with_underscores')
116
- expect(schema.safeParse('token_with_underscores').success).toBe(true)
117
- })
118
-
119
- it('validates token with dots', () => {
120
- const schema = new TokenSchema('token.with.dots')
121
- expect(schema.safeParse('token.with.dots').success).toBe(true)
122
- })
123
-
124
- it('validates token with numbers', () => {
125
- const schema = new TokenSchema('token123')
126
- expect(schema.safeParse('token123').success).toBe(true)
127
- })
128
-
129
- it('validates token with unicode characters', () => {
130
- const schema = new TokenSchema('token世界')
131
- expect(schema.safeParse('token世界').success).toBe(true)
132
- })
133
-
134
- it('validates token with emoji', () => {
135
- const schema = new TokenSchema('token🚀')
136
- expect(schema.safeParse('token🚀').success).toBe(true)
137
- })
138
-
139
- it('validates token with newlines', () => {
140
- const schema = new TokenSchema('token\nwith\nnewlines')
141
- expect(schema.safeParse('token\nwith\nnewlines').success).toBe(true)
142
- expect(schema.safeParse('token with newlines').success).toBe(false)
143
- })
144
-
145
- it('validates token with tabs', () => {
146
- const schema = new TokenSchema('token\twith\ttabs')
147
- expect(schema.safeParse('token\twith\ttabs').success).toBe(true)
148
- })
149
-
150
- it('validates very long token', () => {
151
- const longToken = 'token'.repeat(200)
152
- const schema = new TokenSchema(longToken)
153
- expect(schema.safeParse(longToken).success).toBe(true)
154
- expect(schema.safeParse(longToken + 'x').success).toBe(false)
155
- })
156
- })
157
-
158
- describe('empty token', () => {
159
- const schema = new TokenSchema('')
160
-
161
- it('validates empty string', () => {
162
- const result = schema.safeParse('')
163
- expect(result.success).toBe(true)
164
- if (result.success) {
165
- expect(result.value).toBe('')
166
- }
167
- })
168
-
169
- it('rejects non-empty strings', () => {
170
- const result = schema.safeParse('anything')
171
- expect(result.success).toBe(false)
172
- })
173
-
174
- it('rejects null', () => {
175
- const result = schema.safeParse(null)
176
- expect(result.success).toBe(false)
177
- })
178
-
179
- it('rejects undefined', () => {
180
- const result = schema.safeParse(undefined)
181
- expect(result.success).toBe(false)
182
- })
183
-
184
- it('accepts TokenSchema instance with empty value', () => {
185
- const otherInstance = new TokenSchema('')
186
- const result = schema.safeParse(otherInstance)
187
- expect(result.success).toBe(true)
188
- if (result.success) {
189
- expect(result.value).toBe('')
190
- }
191
- })
192
- })
193
-
194
- describe('whitespace handling', () => {
195
- it('treats whitespace as significant', () => {
196
- const schema = new TokenSchema(' token ')
197
- expect(schema.safeParse(' token ').success).toBe(true)
198
- expect(schema.safeParse('token').success).toBe(false)
199
- expect(schema.safeParse(' token').success).toBe(false)
200
- expect(schema.safeParse('token ').success).toBe(false)
201
- })
202
-
203
- it('distinguishes between different whitespace', () => {
204
- const schema = new TokenSchema('token ')
205
- expect(schema.safeParse('token ').success).toBe(true)
206
- expect(schema.safeParse('token').success).toBe(false)
207
- expect(schema.safeParse('token ').success).toBe(false)
208
- })
209
- })
210
-
211
- describe('case sensitivity', () => {
212
- const schema = new TokenSchema('Token')
213
-
214
- it('is case sensitive', () => {
215
- expect(schema.safeParse('Token').success).toBe(true)
216
- expect(schema.safeParse('token').success).toBe(false)
217
- expect(schema.safeParse('TOKEN').success).toBe(false)
218
- expect(schema.safeParse('ToKeN').success).toBe(false)
219
- })
220
-
221
- it('handles case-sensitive TokenSchema instances', () => {
222
- expect(schema.safeParse(new TokenSchema('Token')).success).toBe(true)
223
- expect(schema.safeParse(new TokenSchema('token')).success).toBe(false)
224
- })
225
- })
226
-
227
- describe('common token patterns', () => {
228
- it('validates namespace-style tokens', () => {
229
- const schema = new TokenSchema('com.example.record')
230
- expect(schema.safeParse('com.example.record').success).toBe(true)
231
- })
232
-
233
- it('validates URL-like tokens', () => {
234
- const schema = new TokenSchema('https://example.com/path')
235
- expect(schema.safeParse('https://example.com/path').success).toBe(true)
236
- })
237
-
238
- it('validates version-like tokens', () => {
239
- const schema = new TokenSchema('v1.0.0')
240
- expect(schema.safeParse('v1.0.0').success).toBe(true)
241
- })
242
-
243
- it('validates hash-like tokens', () => {
244
- const schema = new TokenSchema('#token')
245
- expect(schema.safeParse('#token').success).toBe(true)
246
- })
247
-
248
- it('validates type discriminator tokens', () => {
249
- const schema = new TokenSchema('#post')
250
- expect(schema.safeParse('#post').success).toBe(true)
251
- expect(schema.safeParse('#comment').success).toBe(false)
252
- })
253
- })
254
-
255
121
  describe('serialization methods', () => {
256
- const schema = new TokenSchema('mytoken')
122
+ const schema = token('my.to.ken', 'foo')
257
123
 
258
124
  it('toJSON returns the token value', () => {
259
- expect(schema.toJSON()).toBe('mytoken')
125
+ expect(schema.toJSON()).toBe('my.to.ken#foo')
260
126
  })
261
127
 
262
128
  it('toString returns the token value', () => {
263
- expect(schema.toString()).toBe('mytoken')
129
+ expect(schema.toString()).toBe('my.to.ken#foo')
264
130
  })
265
131
 
266
132
  it('toJSON and toString return the same value', () => {
267
133
  expect(schema.toJSON()).toBe(schema.toString())
268
134
  })
269
135
 
270
- it('handles empty token serialization', () => {
271
- const emptySchema = new TokenSchema('')
272
- expect(emptySchema.toJSON()).toBe('')
273
- expect(emptySchema.toString()).toBe('')
274
- })
275
-
276
- it('handles special characters in serialization', () => {
277
- const specialSchema = new TokenSchema('token\nwith\tspecial')
278
- expect(specialSchema.toJSON()).toBe('token\nwith\tspecial')
279
- expect(specialSchema.toString()).toBe('token\nwith\tspecial')
280
- })
281
-
282
136
  it('serializes to primitive string in JSON', () => {
283
- const schema = new TokenSchema('mytoken')
284
- const obj = { token: schema }
285
- expect(JSON.stringify(obj)).toBe('{"token":"mytoken"}')
137
+ expect(JSON.stringify({ token: schema })).toBe(
138
+ '{"token":"my.to.ken#foo"}',
139
+ )
286
140
  })
287
141
  })
288
142
 
289
143
  describe('value property', () => {
290
- const schema = new TokenSchema('mytoken')
144
+ const schema = token('my.to.ken')
291
145
 
292
146
  it('exposes the token value through serialization', () => {
293
147
  // value is protected, so we verify it through toString/toJSON
294
- expect(schema.toString()).toBe('mytoken')
295
- expect(schema.toJSON()).toBe('mytoken')
296
- })
297
- })
298
-
299
- describe('multiple token instances', () => {
300
- const schema1 = new TokenSchema('token1')
301
- const schema2 = new TokenSchema('token2')
302
- const schema3 = new TokenSchema('token1')
303
-
304
- it('different instances with same value validate each other', () => {
305
- expect(schema1.safeParse(schema3).success).toBe(true)
306
- expect(schema3.safeParse(schema1).success).toBe(true)
307
- })
308
-
309
- it('different instances with different values reject each other', () => {
310
- expect(schema1.safeParse(schema2).success).toBe(false)
311
- expect(schema2.safeParse(schema1).success).toBe(false)
312
- })
313
-
314
- it('validates string values correctly', () => {
315
- expect(schema1.safeParse('token1').success).toBe(true)
316
- expect(schema1.safeParse('token2').success).toBe(false)
317
- expect(schema2.safeParse('token2').success).toBe(true)
318
- expect(schema2.safeParse('token1').success).toBe(false)
319
- })
320
- })
321
-
322
- describe('type safety', () => {
323
- it('preserves token type in TypeScript', () => {
324
- const schema = new TokenSchema('specific' as const)
325
- const result = schema.safeParse('specific')
326
- expect(result.success).toBe(true)
327
- if (result.success) {
328
- // TypeScript should infer result.value as the literal type 'specific'
329
- expect(result.value).toBe('specific')
330
- }
331
- })
332
-
333
- it('handles generic token types', () => {
334
- const schema: TokenSchema<'a' | 'b'> = new TokenSchema('a')
335
- expect(schema.safeParse('a').success).toBe(true)
336
- })
337
- })
338
-
339
- describe('edge cases', () => {
340
- it('handles tokens that look like numbers', () => {
341
- const schema = new TokenSchema('123')
342
- expect(schema.safeParse('123').success).toBe(true)
343
- expect(schema.safeParse(123).success).toBe(false)
344
- })
345
-
346
- it('handles tokens that look like booleans', () => {
347
- const schema = new TokenSchema('true')
348
- expect(schema.safeParse('true').success).toBe(true)
349
- expect(schema.safeParse(true).success).toBe(false)
350
- })
351
-
352
- it('handles tokens that look like null', () => {
353
- const schema = new TokenSchema('null')
354
- expect(schema.safeParse('null').success).toBe(true)
355
- expect(schema.safeParse(null).success).toBe(false)
356
- })
357
-
358
- it('handles tokens that look like undefined', () => {
359
- const schema = new TokenSchema('undefined')
360
- expect(schema.safeParse('undefined').success).toBe(true)
361
- expect(schema.safeParse(undefined).success).toBe(false)
362
- })
363
-
364
- it('handles tokens with only whitespace', () => {
365
- const schema = new TokenSchema(' ')
366
- expect(schema.safeParse(' ').success).toBe(true)
367
- expect(schema.safeParse(' ').success).toBe(false)
368
- expect(schema.safeParse(' ').success).toBe(false)
369
- })
370
-
371
- it('handles single character tokens', () => {
372
- const schema = new TokenSchema('x')
373
- expect(schema.safeParse('x').success).toBe(true)
374
- expect(schema.safeParse('X').success).toBe(false)
375
- expect(schema.safeParse('').success).toBe(false)
376
- })
377
-
378
- it('rejects symbols', () => {
379
- const schema = new TokenSchema('mytoken')
380
- const result = schema.safeParse(Symbol('mytoken'))
381
- expect(result.success).toBe(false)
382
- })
383
-
384
- it('rejects functions', () => {
385
- const schema = new TokenSchema('mytoken')
386
- const result = schema.safeParse(() => 'mytoken')
387
- expect(result.success).toBe(false)
388
- })
389
-
390
- it('rejects dates', () => {
391
- const schema = new TokenSchema('mytoken')
392
- const result = schema.safeParse(new Date())
393
- expect(result.success).toBe(false)
394
- })
395
-
396
- it('rejects regular expressions', () => {
397
- const schema = new TokenSchema('mytoken')
398
- const result = schema.safeParse(/mytoken/)
399
- expect(result.success).toBe(false)
400
- })
401
- })
402
-
403
- describe('comparison with similar schemas', () => {
404
- it('behaves like a string literal validator', () => {
405
- const schema = new TokenSchema('literal')
406
-
407
- // Should only accept the exact string
408
- expect(schema.safeParse('literal').success).toBe(true)
409
- expect(schema.safeParse('other').success).toBe(false)
410
- expect(schema.safeParse('').success).toBe(false)
411
- })
412
-
413
- it('differs from enum by accepting only one value', () => {
414
- const schema = new TokenSchema('option1')
415
-
416
- // Only accepts the single token value
417
- expect(schema.safeParse('option1').success).toBe(true)
418
- expect(schema.safeParse('option2').success).toBe(false)
419
- })
420
-
421
- it('differs from string schema by accepting only specific value', () => {
422
- const schema = new TokenSchema('specific')
423
-
424
- // Only accepts the exact token
425
- expect(schema.safeParse('specific').success).toBe(true)
426
- expect(schema.safeParse('any other string').success).toBe(false)
148
+ expect(schema.toString()).toBe('my.to.ken')
149
+ expect(schema.toJSON()).toBe('my.to.ken')
427
150
  })
428
151
  })
429
152
  })
@@ -1,14 +1,13 @@
1
- import { Schema, ValidationResult, ValidatorContext } from '../core.js'
1
+ import { $type, NsidString, Schema, ValidationContext } from '../core.js'
2
2
 
3
- export class TokenSchema<V extends string = any> extends Schema<V> {
4
- constructor(readonly value: V) {
3
+ export class TokenSchema<
4
+ const TValue extends string = string,
5
+ > extends Schema<TValue> {
6
+ constructor(readonly value: TValue) {
5
7
  super()
6
8
  }
7
9
 
8
- validateInContext(
9
- input: unknown,
10
- ctx: ValidatorContext,
11
- ): ValidationResult<V> {
10
+ validateInContext(input: unknown, ctx: ValidationContext) {
12
11
  if (input === this.value) {
13
12
  return ctx.success(this.value)
14
13
  }
@@ -37,3 +36,11 @@ export class TokenSchema<V extends string = any> extends Schema<V> {
37
36
  return this.value
38
37
  }
39
38
  }
39
+
40
+ /*@__NO_SIDE_EFFECTS__*/
41
+ export function token<
42
+ const N extends NsidString,
43
+ const H extends string = 'main',
44
+ >(nsid: N, hash: H = 'main' as H) {
45
+ return new TokenSchema($type(nsid, hash))
46
+ }