@atproto/lex-schema 0.0.9 → 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 +34 -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 +7 -7
  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 +13 -12
  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
@@ -1,3 +1,3 @@
1
- export declare function memoizedOptions<F extends (options?: NonNullable<unknown>) => any>(fn: F, keyFn?: (options: NonNullable<Parameters<F>[0]>) => string | number | boolean | null | void): F;
2
- export declare function memoizedTransformer<F extends (arg: any) => any>(fn: F): F;
1
+ export declare function memoizedOptions<F extends (...args: any[]) => any>(fn: F): F;
2
+ export declare function memoizedTransformer<F extends (key: any, ...args: any[]) => unknown>(fn: F): F;
3
3
  //# sourceMappingURL=memoize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memoize.d.ts","sourceRoot":"","sources":["../../src/util/memoize.ts"],"names":[],"mappings":"AACA,wBAAgB,eAAe,CAC7B,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,GAAG,EAEjD,EAAE,EAAE,CAAC,EACL,KAAK,CAAC,EAAE,CACN,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KACnC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,GAC3C,CAAC,CAoCH;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CASzE"}
1
+ {"version":3,"file":"memoize.d.ts","sourceRoot":"","sources":["../../src/util/memoize.ts"],"names":[],"mappings":"AACA,wBAAgB,eAAe,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAiB3E;AAGD,wBAAgB,mBAAmB,CACjC,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,EAC/C,EAAE,EAAE,CAAC,GAAG,CAAC,CAaV"}
@@ -3,50 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.memoizedOptions = memoizedOptions;
4
4
  exports.memoizedTransformer = memoizedTransformer;
5
5
  /*@__NO_SIDE_EFFECTS__*/
6
- function memoizedOptions(fn, keyFn) {
7
- let emptyOptionsValue;
8
- if (keyFn) {
9
- const cache = new Map();
10
- const fromCache = (options) => {
11
- const key = keyFn(options);
12
- if (key !== undefined) {
13
- const cached = cache.get(key);
14
- if (cached)
15
- return cached;
16
- const result = fn(options);
17
- cache.set(key, result);
18
- return result;
19
- }
20
- return fn(options);
21
- };
22
- return ((options) => {
23
- // Non-empty options case
24
- if (options)
25
- for (const _ in options)
26
- return fromCache(options);
27
- // Empty or missing options case
28
- return (emptyOptionsValue ??= fn(options));
29
- });
30
- }
31
- return ((options) => {
32
- // Non-empty options case
33
- if (options)
34
- for (const _ in options)
35
- return fn(options);
36
- // Empty or missing options case
37
- return (emptyOptionsValue ??= fn(options));
38
- });
6
+ function memoizedOptions(fn) {
7
+ let cache = null;
8
+ return function cached(...args) {
9
+ // Not using the cache if there are args
10
+ if (args.length > 0) {
11
+ return fn(...args);
12
+ }
13
+ if (cache != null) {
14
+ return cache.value;
15
+ }
16
+ const value = fn(...args);
17
+ cache = { value };
18
+ return value;
19
+ };
39
20
  }
40
21
  /*@__NO_SIDE_EFFECTS__*/
41
22
  function memoizedTransformer(fn) {
42
- const cache = new WeakMap();
43
- return ((arg) => {
44
- const cached = cache.get(arg);
23
+ let cache;
24
+ return function cached(key, ...args) {
25
+ if (args.length > 0)
26
+ return fn(key, ...args);
27
+ cache ??= new WeakMap();
28
+ const cached = cache.get(key);
45
29
  if (cached)
46
30
  return cached;
47
- const result = fn(arg);
48
- cache.set(arg, result);
31
+ const result = fn(key, ...args);
32
+ cache.set(key, result);
49
33
  return result;
50
- });
34
+ };
51
35
  }
52
36
  //# sourceMappingURL=memoize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memoize.js","sourceRoot":"","sources":["../../src/util/memoize.ts"],"names":[],"mappings":";;AACA,0CA2CC;AAGD,kDASC;AAxDD,wBAAwB;AACxB,SAAgB,eAAe,CAG7B,EAAK,EACL,KAE4C;IAE5C,IAAI,iBAA4C,CAAA;IAEhD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmD,CAAA;QACxE,MAAM,SAAS,GAAG,CAChB,OAAsC,EACvB,EAAE;YACjB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAA;YAC1B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;gBAC7B,IAAI,MAAM;oBAAE,OAAO,MAAM,CAAA;gBACzB,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAkB,CAAA;gBAC3C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;gBACtB,OAAO,MAAM,CAAA;YACf,CAAC;YAED,OAAO,EAAE,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC,CAAA;QAED,OAAO,CAAC,CAAC,OAAyB,EAAiB,EAAE;YACnD,yBAAyB;YACzB,IAAI,OAAO;gBAAE,KAAK,MAAM,CAAC,IAAI,OAAO;oBAAE,OAAO,SAAS,CAAC,OAAO,CAAC,CAAA;YAE/D,gCAAgC;YAChC,OAAO,CAAC,iBAAiB,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;QAC5C,CAAC,CAAM,CAAA;IACT,CAAC;IAED,OAAO,CAAC,CAAC,OAAyB,EAAiB,EAAE;QACnD,yBAAyB;QACzB,IAAI,OAAO;YAAE,KAAK,MAAM,CAAC,IAAI,OAAO;gBAAE,OAAO,EAAE,CAAC,OAAO,CAAC,CAAA;QAExD,gCAAgC;QAChC,OAAO,CAAC,iBAAiB,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAC5C,CAAC,CAAM,CAAA;AACT,CAAC;AAED,wBAAwB;AACxB,SAAgB,mBAAmB,CAA8B,EAAK;IACpE,MAAM,KAAK,GAAG,IAAI,OAAO,EAAyB,CAAA;IAClD,OAAO,CAAC,CAAC,GAAqB,EAAiB,EAAE;QAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QACzB,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,CAAkB,CAAA;QACvC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACtB,OAAO,MAAM,CAAA;IACf,CAAC,CAAM,CAAA;AACT,CAAC","sourcesContent":["/*@__NO_SIDE_EFFECTS__*/\nexport function memoizedOptions<\n F extends (options?: NonNullable<unknown>) => any,\n>(\n fn: F,\n keyFn?: (\n options: NonNullable<Parameters<F>[0]>,\n ) => string | number | boolean | null | void,\n): F {\n let emptyOptionsValue: ReturnType<F> | undefined\n\n if (keyFn) {\n const cache = new Map<string | number | boolean | null, ReturnType<F>>()\n const fromCache = (\n options: NonNullable<Parameters<F>[0]>,\n ): ReturnType<F> => {\n const key = keyFn(options)\n if (key !== undefined) {\n const cached = cache.get(key)\n if (cached) return cached\n const result = fn(options) as ReturnType<F>\n cache.set(key, result)\n return result\n }\n\n return fn(options)\n }\n\n return ((options: Parameters<F>[0]): ReturnType<F> => {\n // Non-empty options case\n if (options) for (const _ in options) return fromCache(options)\n\n // Empty or missing options case\n return (emptyOptionsValue ??= fn(options))\n }) as F\n }\n\n return ((options: Parameters<F>[0]): ReturnType<F> => {\n // Non-empty options case\n if (options) for (const _ in options) return fn(options)\n\n // Empty or missing options case\n return (emptyOptionsValue ??= fn(options))\n }) as F\n}\n\n/*@__NO_SIDE_EFFECTS__*/\nexport function memoizedTransformer<F extends (arg: any) => any>(fn: F): F {\n const cache = new WeakMap<object, ReturnType<F>>()\n return ((arg: Parameters<F>[0]): ReturnType<F> => {\n const cached = cache.get(arg)\n if (cached) return cached\n const result = fn(arg) as ReturnType<F>\n cache.set(arg, result)\n return result\n }) as F\n}\n"]}
1
+ {"version":3,"file":"memoize.js","sourceRoot":"","sources":["../../src/util/memoize.ts"],"names":[],"mappings":";;AACA,0CAiBC;AAGD,kDAeC;AApCD,wBAAwB;AACxB,SAAgB,eAAe,CAAoC,EAAK;IACtE,IAAI,KAAK,GAAoC,IAAI,CAAA;IAEjD,OAAO,SAAS,MAAM,CAAC,GAAG,IAAW;QACnC,wCAAwC;QACxC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;QACpB,CAAC;QAED,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC,KAAK,CAAA;QACpB,CAAC;QAED,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;QACzB,KAAK,GAAG,EAAE,KAAK,EAAE,CAAA;QACjB,OAAO,KAAK,CAAA;IACd,CAAM,CAAA;AACR,CAAC;AAED,wBAAwB;AACxB,SAAgB,mBAAmB,CAEjC,EAAK;IACL,IAAI,KAAqC,CAAA;IAEzC,OAAO,SAAS,MAAM,CAAC,GAAQ,EAAE,GAAG,IAAW;QAC7C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QAE5C,KAAK,KAAK,IAAI,OAAO,EAAE,CAAA;QACvB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QACzB,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAkB,CAAA;QAChD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACtB,OAAO,MAAM,CAAA;IACf,CAAM,CAAA;AACR,CAAC","sourcesContent":["/*@__NO_SIDE_EFFECTS__*/\nexport function memoizedOptions<F extends (...args: any[]) => any>(fn: F): F {\n let cache: null | { value: ReturnType<F> } = null\n\n return function cached(...args: any[]): ReturnType<F> {\n // Not using the cache if there are args\n if (args.length > 0) {\n return fn(...args)\n }\n\n if (cache != null) {\n return cache.value\n }\n\n const value = fn(...args)\n cache = { value }\n return value\n } as F\n}\n\n/*@__NO_SIDE_EFFECTS__*/\nexport function memoizedTransformer<\n F extends (key: any, ...args: any[]) => unknown,\n>(fn: F): F {\n let cache: WeakMap<object, ReturnType<F>>\n\n return function cached(key: any, ...args: any[]): any {\n if (args.length > 0) return fn(key, ...args)\n\n cache ??= new WeakMap()\n const cached = cache.get(key)\n if (cached) return cached\n const result = fn(key, ...args) as ReturnType<F>\n cache.set(key, result)\n return result\n } as F\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/lex-schema",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "license": "MIT",
5
5
  "description": "Lexicon schema system for AT Lexicons",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "tslib": "^2.8.1",
39
- "@atproto/syntax": "0.4.2",
40
- "@atproto/lex-data": "0.0.8"
39
+ "@atproto/syntax": "0.4.3",
40
+ "@atproto/lex-data": "0.0.9"
41
41
  },
42
42
  "devDependencies": {
43
43
  "vitest": "^4.0.16"
@@ -0,0 +1,20 @@
1
+ import { describe, it } from 'vitest'
2
+ import { LexMap } from '@atproto/lex-data'
3
+ import { Unknown$TypedObject } from './$type.js'
4
+
5
+ describe('Unknown$TypedObject', () => {
6
+ it('allows assigning Unknown$TypedObject to LexMap', () => {
7
+ function expectLexMap(_value: LexMap) {}
8
+
9
+ const someObject = {
10
+ $type: 'some-type',
11
+ } as Unknown$TypedObject
12
+
13
+ expectLexMap(someObject)
14
+
15
+ expectLexMap({
16
+ arr: [someObject],
17
+ val: someObject,
18
+ })
19
+ })
20
+ })
package/src/core/$type.ts CHANGED
@@ -28,6 +28,13 @@ export type $Typed<V, T extends string = string> = Simplify<
28
28
  }
29
29
  >
30
30
 
31
+ export function $typed<V extends { $type?: unknown }, T extends string>(
32
+ value: V,
33
+ $type: T,
34
+ ): $Typed<V, T> {
35
+ return value.$type === $type ? (value as $Typed<V, T>) : { ...value, $type }
36
+ }
37
+
31
38
  export type $TypedMaybe<V, T extends string = string> = Simplify<
32
39
  V & {
33
40
  $type?: T
@@ -35,3 +42,26 @@ export type $TypedMaybe<V, T extends string = string> = Simplify<
35
42
  >
36
43
 
37
44
  export type Un$Typed<V extends { $type?: string }> = OmitKey<V, '$type'>
45
+
46
+ declare const unknown$TypeSymbol: unique symbol
47
+ export type Unknown$Type = string & { [unknown$TypeSymbol]: true }
48
+
49
+ // In order to prevent places that expect a union of known and unknown $typed
50
+ // objects (like lexicons schema open unions), from accepting an invalid version
51
+ // of the known $typed objects, we need to prevent any other properties from
52
+ // being present.
53
+ //
54
+ // For example, if we expect:
55
+ // ```ts
56
+ // type MyOpenUnion = { $type: 'A'; a: number } | Unknown$TypedObject
57
+ // ```
58
+ // we want to make that that the following is rejected:
59
+ // ```ts
60
+ // { $type: 'A' }
61
+ // ```
62
+ //
63
+ // If we typed `Unknown$TypedObject` as `{ $type: string }`, `{ $type: 'A' }`
64
+ // would be a valid `MyOpenUnion` as it would match the `Unknown$TypedObject`.
65
+ // By using a $type property that uniquely describes unknown values, we ensure
66
+ // that only valid known typed objects, or a type casted value, can be used.
67
+ export type Unknown$TypedObject = { $type: Unknown$Type }
@@ -1,17 +1,38 @@
1
1
  import {
2
+ InferInput,
3
+ InferOutput,
4
+ ValidationContext,
2
5
  ValidationOptions,
3
6
  ValidationResult,
4
7
  Validator,
5
- ValidatorContext,
6
8
  } from './validator.js'
7
9
 
8
- export abstract class Schema<Output = any> implements Validator<Output> {
9
- declare readonly ['__lex']: { output: Output }
10
+ type ParseOptions = Omit<ValidationOptions, 'mode'>
11
+ type ValidateOptions = Omit<ValidationOptions, 'mode'>
12
+
13
+ export interface SchemaInternals<out TInput = unknown, out TOutput = TInput> {
14
+ /** @internal The inferred validation type */
15
+ input: TInput
16
+
17
+ /** @internal The inferred parse type */
18
+ output: TOutput
19
+ }
20
+
21
+ export abstract class Schema<
22
+ out TInput = unknown,
23
+ out TOutput = TInput,
24
+ out TInternals extends SchemaInternals<TInput, TOutput> = SchemaInternals<
25
+ TInput,
26
+ TOutput
27
+ >,
28
+ > implements Validator<TInternals['input'], TInternals['output']>
29
+ {
30
+ declare readonly ['__lex']: TInternals
10
31
 
11
32
  abstract validateInContext(
12
33
  input: unknown,
13
- ctx: ValidatorContext,
14
- ): ValidationResult<Output>
34
+ ctx: ValidationContext,
35
+ ): ValidationResult
15
36
 
16
37
  /**
17
38
  * @note use {@link check}() instead of {@link assert}() if you encounter a
@@ -19,8 +40,8 @@ export abstract class Schema<Output = any> implements Validator<Output> {
19
40
  * will typically arise in generic contexts, where the narrowed type is not
20
41
  * needed.
21
42
  */
22
- assert(input: unknown): asserts input is Output {
23
- const result = this.safeParse(input, { allowTransform: false })
43
+ assert(input: unknown): asserts input is InferInput<this> {
44
+ const result = ValidationContext.validate(input, this)
24
45
  if (!result.success) throw result.reason
25
46
  }
26
47
 
@@ -37,45 +58,53 @@ export abstract class Schema<Output = any> implements Validator<Output> {
37
58
  /**
38
59
  * Casts the input (by validating it) to the output type if it matches the
39
60
  * schema, otherwise throws. This is the same as calling {@link parse}() with
40
- * `allowTransform: false`.
61
+ * `mode: "validate"`.
41
62
  */
42
- cast<I>(input: I): I & Output {
43
- return this.parse(input, { allowTransform: false })
63
+ cast<I>(input: I): I & InferInput<this> {
64
+ const result = ValidationContext.validate(input, this)
65
+ if (result.success) return result.value
66
+ throw result.reason
44
67
  }
45
68
 
46
- matches(input: unknown): input is Output {
47
- const result = this.safeParse(input, { allowTransform: false })
69
+ matches<I>(input: I): input is I & InferInput<this> {
70
+ const result = ValidationContext.validate(input, this)
48
71
  return result.success
49
72
  }
50
73
 
51
- ifMatches<I>(input: I): (I & Output) | undefined {
74
+ ifMatches<I>(input: I): (I & InferInput<this>) | undefined {
52
75
  return this.matches(input) ? input : undefined
53
76
  }
54
77
 
55
- parse<I>(
56
- input: I,
57
- options: ValidationOptions & { allowTransform: false },
58
- ): I & Output
59
- parse(input: unknown, options?: ValidationOptions): Output
60
- parse(input: unknown, options?: ValidationOptions): Output {
78
+ parse(input: unknown, options?: ParseOptions): InferOutput<this> {
61
79
  const result = this.safeParse(input, options)
62
- if (!result.success) throw result.reason
63
- return result.value
80
+ if (result.success) return result.value
81
+ throw result.reason
64
82
  }
65
83
 
66
- safeParse<I>(
67
- input: I,
68
- options: ValidationOptions & { allowTransform: false },
69
- ): ValidationResult<I & Output>
70
- safeParse(
71
- input: unknown,
72
- options?: ValidationOptions,
73
- ): ValidationResult<Output>
74
84
  safeParse(
75
85
  input: unknown,
76
- options?: ValidationOptions,
77
- ): ValidationResult<Output> {
78
- return ValidatorContext.validate(input, this, options)
86
+ options?: ParseOptions,
87
+ ): ValidationResult<InferOutput<this>> {
88
+ return ValidationContext.validate(input, this, {
89
+ ...options,
90
+ mode: 'parse',
91
+ })
92
+ }
93
+
94
+ validate<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
95
+ const result = this.safeValidate(input, options)
96
+ if (result.success) return result.value
97
+ throw result.reason
98
+ }
99
+
100
+ safeValidate<I>(
101
+ input: I,
102
+ options?: ValidateOptions,
103
+ ): ValidationResult<I & InferInput<this>> {
104
+ return ValidationContext.validate(input, this, {
105
+ ...options,
106
+ mode: 'validate',
107
+ })
79
108
  }
80
109
 
81
110
  // @NOTE The built lexicons namespaces will export utility functions that
@@ -92,26 +121,45 @@ export abstract class Schema<Output = any> implements Validator<Output> {
92
121
  // - "app.bsky.feed.post.$parse(...)" // calls a utility function created by "lex build"
93
122
  // - "app.bsky.feed.defs.postView.$parse(...)" // uses the alias defined below on the schema instance
94
123
 
95
- $assert(input: unknown): asserts input is Output {
124
+ $assert(input: unknown): asserts input is InferInput<this> {
96
125
  return this.assert(input)
97
126
  }
98
127
 
99
- $matches(input: unknown): input is Output {
128
+ $check(input: unknown): void {
129
+ return this.check(input)
130
+ }
131
+
132
+ $cast<I>(input: I): I & InferInput<this> {
133
+ return this.cast(input)
134
+ }
135
+
136
+ $matches(input: unknown): input is InferInput<this> {
100
137
  return this.matches(input)
101
138
  }
102
139
 
103
- $ifMatches<I>(input: I): (I & Output) | undefined {
140
+ $ifMatches<I>(input: I): (I & InferInput<this>) | undefined {
104
141
  return this.ifMatches(input)
105
142
  }
106
143
 
107
- $parse(input: unknown, options?: ValidationOptions): Output {
144
+ $parse(input: unknown, options?: ValidateOptions): InferOutput<this> {
108
145
  return this.parse(input, options)
109
146
  }
110
147
 
111
148
  $safeParse(
112
149
  input: unknown,
113
- options?: ValidationOptions,
114
- ): ValidationResult<Output> {
150
+ options?: ValidateOptions,
151
+ ): ValidationResult<InferOutput<this>> {
115
152
  return this.safeParse(input, options)
116
153
  }
154
+
155
+ $validate<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
156
+ return this.validate(input, options)
157
+ }
158
+
159
+ $safeValidate<I>(
160
+ input: I,
161
+ options?: ValidateOptions,
162
+ ): ValidationResult<I & InferInput<this>> {
163
+ return this.safeValidate(input, options)
164
+ }
117
165
  }
@@ -1,4 +1,4 @@
1
- import { ensureValidCidString, isLanguageString } from '@atproto/lex-data'
1
+ import { validateCidString } from '@atproto/lex-data'
2
2
  import {
3
3
  AtIdentifierString,
4
4
  AtUriString,
@@ -8,173 +8,134 @@ import {
8
8
  NsidString,
9
9
  RecordKeyString,
10
10
  TidString,
11
- ensureValidAtIdentifier,
12
- ensureValidAtUri,
13
- ensureValidDatetime,
14
- ensureValidDid,
15
- ensureValidHandle,
16
- ensureValidNsid,
17
- ensureValidRecordKey,
18
- ensureValidTid,
11
+ UriString,
12
+ isValidAtIdentifier as isValidAtId,
13
+ isValidAtUri,
14
+ isValidDatetime,
15
+ isValidDid,
16
+ isValidHandle,
17
+ isValidLanguage,
18
+ isValidNsid,
19
+ isValidRecordKey,
20
+ isValidTid,
21
+ isValidUri,
19
22
  } from '@atproto/syntax'
20
- import {
21
- AssertFn,
22
- CastFn,
23
- CheckFn,
24
- createAssertFunction,
25
- createCastFunction,
26
- createCheckFunction,
27
- } from '../util/assertion-util.js'
28
-
29
- // Format utilities missing from @atproto/syntax
23
+ import { CheckFn } from '../util/assertion-util.js'
24
+
25
+ // Expose all individual string format types and type guards
26
+
27
+ export type { AtIdentifierString }
28
+ export const isAtIdentifierString: CheckFn<AtIdentifierString> = isValidAtId
29
+
30
+ export type { AtUriString }
31
+ export const isAtUriString: CheckFn<AtUriString> = isValidAtUri
32
+
30
33
  export type CidString = string
34
+ export const isCidString = ((v) => validateCidString(v)) as CheckFn<CidString>
35
+
36
+ export type { DatetimeString }
37
+ export const isDatetimeString: CheckFn<DatetimeString> = isValidDatetime
38
+
39
+ export type { DidString }
40
+ export const isDidString: CheckFn<DidString> = isValidDid
41
+
42
+ export type { HandleString }
43
+ export const isHandleString: CheckFn<HandleString> = isValidHandle
44
+
31
45
  export type LanguageString = string
32
- export type UriString = `${string}:${string}`
46
+ export const isLanguageString = isValidLanguage as CheckFn<LanguageString>
33
47
 
34
- /*@__NO_SIDE_EFFECTS__*/
35
- export function isUriString<T extends string>(
36
- input: T,
37
- ): input is T & UriString {
38
- return /^\w+:(?:\/\/)?[^\s/][^\s]*$/.test(input)
48
+ export type { NsidString }
49
+ export const isNsidString: CheckFn<NsidString> = isValidNsid
50
+
51
+ export type { RecordKeyString }
52
+ export const isRecordKeyString: CheckFn<RecordKeyString> = isValidRecordKey
53
+
54
+ export type { TidString }
55
+ export const isTidString: CheckFn<TidString> = isValidTid
56
+
57
+ export type { UriString }
58
+ export const isUriString: CheckFn<UriString> = isValidUri
59
+
60
+ // String format registry (maps format names to their types and type guards)
61
+
62
+ type StringFormats = {
63
+ 'at-identifier': AtIdentifierString
64
+ 'at-uri': AtUriString
65
+ cid: CidString
66
+ datetime: DatetimeString
67
+ did: DidString
68
+ handle: HandleString
69
+ language: LanguageString
70
+ nsid: NsidString
71
+ 'record-key': RecordKeyString
72
+ tid: TidString
73
+ uri: UriString
39
74
  }
40
75
 
41
- // Re-export utility typed as assertion functions so that TypeScript can
42
- // infer the narrowed type after calling them.
76
+ export type StringFormat = Extract<keyof StringFormats, string>
43
77
 
44
- export type {
45
- AtIdentifierString,
46
- AtUriString,
47
- DatetimeString,
48
- DidString,
49
- HandleString,
50
- NsidString,
51
- RecordKeyString,
52
- TidString,
53
- } from '@atproto/syntax'
78
+ const stringFormatVerifiers: {
79
+ readonly [K in StringFormat]: CheckFn<StringFormats[K]>
80
+ } = /*#__PURE__*/ Object.freeze({
81
+ __proto__: null,
82
+
83
+ 'at-identifier': isAtIdentifierString,
84
+ 'at-uri': isAtUriString,
85
+ cid: isCidString,
86
+ datetime: isDatetimeString,
87
+ did: isDidString,
88
+ handle: isHandleString,
89
+ language: isLanguageString,
90
+ nsid: isNsidString,
91
+ 'record-key': isRecordKeyString,
92
+ tid: isTidString,
93
+ uri: isUriString,
94
+ })
54
95
 
55
- // Export utilities for formats missing from @atproto/syntax
56
-
57
- export const assertAtIdentifierString: AssertFn<AtIdentifierString> =
58
- ensureValidAtIdentifier
59
- export const assertAtUriString: AssertFn<AtUriString> = ensureValidAtUri
60
- export const assertCidString: AssertFn<CidString> = ensureValidCidString
61
- export const assertDatetimeString: AssertFn<DatetimeString> =
62
- ensureValidDatetime
63
- export const assertDidString: AssertFn<DidString> = ensureValidDid
64
- export const assertHandleString: AssertFn<HandleString> = ensureValidHandle
65
- export const assertLanguageString: AssertFn<LanguageString> =
66
- createAssertFunction<LanguageString>(
67
- isLanguageString,
68
- 'Invalid BCP 47 string',
69
- )
70
- export const assertNsidString: AssertFn<NsidString> = ensureValidNsid
71
- export const assertRecordKeyString: AssertFn<RecordKeyString> =
72
- ensureValidRecordKey
73
- export const assertTidString: AssertFn<TidString> = ensureValidTid
74
- export const assertUriString: AssertFn<UriString> =
75
- createAssertFunction<UriString>(isUriString, 'Invalid URI')
76
-
77
- export const asAtIdentifierString: CastFn<AtIdentifierString> =
78
- /*#__PURE__*/ createCastFunction(assertAtIdentifierString)
79
- export const asAtUriString: CastFn<AtUriString> =
80
- /*#__PURE__*/ createCastFunction(ensureValidAtUri)
81
- export const asCidString: CastFn<CidString> =
82
- /*#__PURE__*/ createCastFunction(ensureValidCidString)
83
- export const asDatetimeString: CastFn<DatetimeString> =
84
- /*#__PURE__*/ createCastFunction(ensureValidDatetime)
85
- export const asDidString: CastFn<DidString> =
86
- /*#__PURE__*/ createCastFunction(ensureValidDid)
87
- export const asHandleString: CastFn<HandleString> =
88
- /*#__PURE__*/ createCastFunction(ensureValidHandle)
89
- export const asLanguageString: CastFn<LanguageString> =
90
- /*#__PURE__*/ createCastFunction(assertLanguageString)
91
- export const asNsidString: CastFn<NsidString> =
92
- /*#__PURE__*/ createCastFunction(ensureValidNsid)
93
- export const asRecordKeyString: CastFn<RecordKeyString> =
94
- /*#__PURE__*/ createCastFunction(ensureValidRecordKey)
95
- export const asTidString: CastFn<TidString> =
96
- /*#__PURE__*/ createCastFunction(ensureValidTid)
97
- export const asUriString: CastFn<UriString> =
98
- /*#__PURE__*/ createCastFunction(assertUriString)
99
-
100
- export { isLanguageString }
101
- export const isAtIdentifierString: CheckFn<AtIdentifierString> =
102
- /*#__PURE__*/ createCheckFunction(assertAtIdentifierString)
103
- export const isAtUriString: CheckFn<AtUriString> =
104
- /*#__PURE__*/ createCheckFunction(assertAtIdentifierString)
105
- export const isCidString: CheckFn<CidString> =
106
- /*#__PURE__*/ createCheckFunction(assertCidString)
107
- export const isDatetimeString: CheckFn<DatetimeString> =
108
- /*#__PURE__*/ createCheckFunction(assertDatetimeString)
109
- export const isDidString: CheckFn<DidString> =
110
- /*#__PURE__*/ createCheckFunction(assertDidString)
111
- export const isHandleString: CheckFn<HandleString> =
112
- /*#__PURE__*/ createCheckFunction(assertHandleString)
113
- export const isNsidString: CheckFn<NsidString> =
114
- /*#__PURE__*/ createCheckFunction(assertNsidString)
115
- export const isRecordKeyString: CheckFn<RecordKeyString> =
116
- /*#__PURE__*/ createCheckFunction(assertRecordKeyString)
117
- export const isTidString: CheckFn<TidString> =
118
- /*#__PURE__*/ createCheckFunction(assertTidString)
119
-
120
- // String formatting types and utilities
121
-
122
- export const STRING_FORMATS = Object.freeze([
123
- 'datetime',
124
- 'uri',
125
- 'at-uri',
126
- 'did',
127
- 'handle',
128
- 'at-identifier',
129
- 'nsid',
130
- 'cid',
131
- 'language',
132
- 'tid',
133
- 'record-key',
134
- ] as const)
135
-
136
- export type StringFormat = (typeof STRING_FORMATS)[number]
137
-
138
- export type InferStringFormat<F> =
139
- //
140
- F extends 'datetime'
141
- ? DatetimeString
142
- : F extends 'uri'
143
- ? UriString
144
- : F extends 'at-uri'
145
- ? AtUriString
146
- : F extends 'did'
147
- ? DidString
148
- : F extends 'handle'
149
- ? HandleString
150
- : F extends 'at-identifier'
151
- ? AtIdentifierString
152
- : F extends 'nsid'
153
- ? NsidString
154
- : // LanguageString | CidString | TidString | RecordKeyString
155
- string
156
-
157
- const formatters = /*#__PURE__*/ new Map<StringFormat, (str: string) => void>([
158
- ['at-identifier', assertAtIdentifierString],
159
- ['at-uri', assertAtUriString],
160
- ['cid', assertCidString],
161
- ['datetime', assertDatetimeString],
162
- ['did', assertDidString],
163
- ['handle', assertHandleString],
164
- ['language', assertLanguageString],
165
- ['nsid', assertNsidString],
166
- ['record-key', assertRecordKeyString],
167
- ['tid', assertTidString],
168
- ['uri', assertUriString],
169
- ] as const)
96
+ export type InferStringFormat<F extends StringFormat> = F extends StringFormat
97
+ ? StringFormats[F]
98
+ : never
170
99
 
171
100
  /*@__NO_SIDE_EFFECTS__*/
172
- export function assertStringFormat<F extends StringFormat>(
173
- input: string,
101
+ export function isStringFormat<I extends string, F extends StringFormat>(
102
+ input: I,
174
103
  format: F,
175
- ): asserts input is InferStringFormat<F> {
176
- const assertFn = formatters.get(format)
177
- if (assertFn) assertFn(input)
104
+ ): input is I & StringFormats[F] {
105
+ const formatVerifier = stringFormatVerifiers[format]
178
106
  // Fool-proof
179
- else throw new Error(`Unknown string format: ${format}`)
107
+ if (!formatVerifier) throw new TypeError(`Unknown string format: ${format}`)
108
+
109
+ return formatVerifier(input)
110
+ }
111
+
112
+ /*@__NO_SIDE_EFFECTS__*/
113
+ export function assertStringFormat<I extends string, F extends StringFormat>(
114
+ input: I,
115
+ format: F,
116
+ ): asserts input is I & StringFormats[F] {
117
+ if (!isStringFormat(input, format)) {
118
+ throw new TypeError(`Invalid string format (${format}): ${input}`)
119
+ }
180
120
  }
121
+
122
+ /*@__NO_SIDE_EFFECTS__*/
123
+ export function asStringFormat<I extends string, F extends StringFormat>(
124
+ input: I,
125
+ format: F,
126
+ ): I & StringFormats[F] {
127
+ assertStringFormat(input, format)
128
+ return input
129
+ }
130
+
131
+ /*@__NO_SIDE_EFFECTS__*/
132
+ export function ifStringFormat<I extends string, F extends StringFormat>(
133
+ input: I,
134
+ format: F,
135
+ ): undefined | (I & StringFormats[F]) {
136
+ return isStringFormat(input, format) ? input : undefined
137
+ }
138
+
139
+ export const STRING_FORMATS = /*#__PURE__*/ Object.freeze(
140
+ /*#__PURE__*/ Object.keys(stringFormatVerifiers),
141
+ ) as readonly StringFormat[]