@@ -24,12 +24,21 @@ defmodule Atex.Lexicon do
24
24
|> then ( & Recase.Enumerable . atomize_keys / 1 )
25
25
|> then ( & Atex.Lexicon.Schema . lexicon! / 1 )
26
26
27
- # TODO: support returning typedefs
28
27
defs =
29
28
lexicon . defs
30
29
|> Enum . flat_map ( fn { def_name , def } -> def_to_schema ( lexicon . id , def_name , def ) end )
31
- |> Enum . map ( fn { schema_key , quoted_schema } ->
30
+ |> Enum . map ( fn { schema_key , quoted_schema , quoted_type } ->
31
+ identity_type =
32
+ if schema_key === :main do
33
+ quote do
34
+ @ type t ( ) :: unquote ( quoted_type )
35
+ end
36
+ end
37
+
32
38
quote do
39
+ @ type unquote ( schema_key ) ( ) :: unquote ( quoted_type )
40
+ unquote ( identity_type )
41
+
33
42
defschema unquote ( schema_key ) , unquote ( quoted_schema )
34
43
end
35
44
end )
@@ -41,15 +50,15 @@ defmodule Atex.Lexicon do
41
50
end
42
51
end
43
52
44
- # TODO: generate typedefs
45
53
@ spec def_to_schema ( nsid :: String . t ( ) , def_name :: String . t ( ) , lexicon_def :: map ( ) ) ::
46
- list ( { key :: atom ( ) , quoted :: term ( ) } )
54
+ list ( { key :: atom ( ) , quoted_schema :: term ( ) , quoted_type :: term ( ) } )
47
55
48
56
defp def_to_schema ( nsid , def_name , % { type: "record" , record: record } ) do
49
57
# TODO: record rkey format validator
50
58
def_to_schema ( nsid , def_name , record )
51
59
end
52
60
61
+ # TODO: add `$type` field. It's just a string though.
53
62
defp def_to_schema (
54
63
nsid ,
55
64
def_name ,
@@ -63,15 +72,39 @@ defmodule Atex.Lexicon do
63
72
64
73
properties
65
74
|> Enum . map ( fn { key , field } ->
66
- field_to_schema ( field , nsid )
67
- |> then (
68
- & if key in nullable , do: quote ( do: { :either , { { :literal , nil } , unquote ( & 1 ) } } ) , else: & 1
69
- )
70
- |> then ( & if key in required , do: quote ( do: { :required , unquote ( & 1 ) } ) , else: & 1 )
71
- |> then ( & { key , & 1 } )
75
+ { quoted_schema , quoted_type } = field_to_schema ( field , nsid )
76
+ is_nullable = key in nullable
77
+ is_required = key in required
78
+
79
+ quoted_schema =
80
+ quoted_schema
81
+ |> then (
82
+ & if is_nullable , do: quote ( do: { :either , { { :literal , nil } , unquote ( & 1 ) } } ) , else: & 1
83
+ )
84
+ |> then ( & if is_required , do: quote ( do: { :required , unquote ( & 1 ) } ) , else: & 1 )
85
+ |> then ( & { key , & 1 } )
86
+
87
+ key_type = if is_required , do: :required , else: :optional
88
+
89
+ quoted_type =
90
+ quoted_type
91
+ |> then (
92
+ & if is_nullable do
93
+ { :| , [ ] , [ & 1 , nil ] }
94
+ else
95
+ & 1
96
+ end
97
+ )
98
+ |> then ( & { { key_type , [ ] , [ key ] } , & 1 } )
99
+
100
+ { quoted_schema , quoted_type }
101
+ end )
102
+ |> Enum . reduce ( { [ ] , [ ] } , fn { quoted_schema , quoted_type } , { schemas , types } ->
103
+ { [ quoted_schema | schemas ] , [ quoted_type | types ] }
104
+ end )
105
+ |> then ( fn { quoted_schemas , quoted_types } ->
106
+ [ { atomise ( def_name ) , { :%{} , [ ] , quoted_schemas } , { :%{} , [ ] , quoted_types } } ]
72
107
end )
73
- |> then ( & { :%{} , [ ] , & 1 } )
74
- |> then ( & [ { atomise ( def_name ) , & 1 } ] )
75
108
end
76
109
77
110
# TODO: validating errors?
@@ -154,7 +187,15 @@ defmodule Atex.Lexicon do
154
187
155
188
defp def_to_schema ( _nsid , def_name , % { type: "token" } ) do
156
189
# TODO: make it a validator that expects the nsid + key.
157
- [ { atomise ( def_name ) , :string } ]
190
+ [
191
+ {
192
+ atomise ( def_name ) ,
193
+ :string ,
194
+ quote do
195
+ String . t ( )
196
+ end
197
+ }
198
+ ]
158
199
end
159
200
160
201
defp def_to_schema ( nsid , def_name , % { type: type } = def )
@@ -168,10 +209,12 @@ defmodule Atex.Lexicon do
168
209
"cid-link" ,
169
210
"unknown"
170
211
] do
171
- [ { atomise ( def_name ) , field_to_schema ( def , nsid ) } ]
212
+ { quoted_schema , quoted_type } = field_to_schema ( def , nsid )
213
+ [ { atomise ( def_name ) , quoted_schema , quoted_type } ]
172
214
end
173
215
174
- @ spec field_to_schema ( field_def :: % { type: String . t ( ) } , nsid :: String . t ( ) ) :: Peri . schema_def ( )
216
+ @ spec field_to_schema ( field_def :: % { type: String . t ( ) } , nsid :: String . t ( ) ) ::
217
+ { quoted_schema :: term ( ) , quoted_typespec :: term ( ) }
175
218
defp field_to_schema ( % { type: "string" } = field , _nsid ) do
176
219
fixed_schema = const_or_enum ( field )
177
220
@@ -189,14 +232,24 @@ defmodule Atex.Lexicon do
189
232
|> Enum . map ( fn { k , v } -> { Recase . to_snake ( k ) , v } end )
190
233
|> then ( & { :custom , { Validators.String , :validate , [ & 1 ] } } )
191
234
|> maybe_default ( field )
192
- |> then ( & Macro . escape / 1 )
235
+ |> then (
236
+ & { Macro . escape ( & 1 ) ,
237
+ quote do
238
+ String . t ( )
239
+ end }
240
+ )
193
241
end
194
242
end
195
243
196
244
defp field_to_schema ( % { type: "boolean" } = field , _nsid ) do
197
245
( const ( field ) || :boolean )
198
246
|> maybe_default ( field )
199
- |> then ( & Macro . escape / 1 )
247
+ |> then (
248
+ & { Macro . escape ( & 1 ) ,
249
+ quote do
250
+ boolean ( )
251
+ end }
252
+ )
200
253
end
201
254
202
255
defp field_to_schema ( % { type: "integer" } = field , _nsid ) do
@@ -211,11 +264,19 @@ defmodule Atex.Lexicon do
211
264
|> then ( & { :custom , { Validators.Integer , [ & 1 ] } } )
212
265
|> maybe_default ( field )
213
266
end
214
- |> then ( & Macro . escape / 1 )
267
+ |> then (
268
+ & {
269
+ Macro . escape ( & 1 ) ,
270
+ # TODO: turn into range definition based on maximum/minimum
271
+ quote do
272
+ integer ( )
273
+ end
274
+ }
275
+ )
215
276
end
216
277
217
278
defp field_to_schema ( % { type: "array" , items: items } = field , nsid ) do
218
- inner_schema = field_to_schema ( items , nsid )
279
+ { inner_schema , inner_type } = field_to_schema ( items , nsid )
219
280
220
281
field
221
282
|> Map . take ( [ :maxLength , :minLength ] )
@@ -228,27 +289,48 @@ defmodule Atex.Lexicon do
228
289
{ inner_schema , _ } = Code . eval_quoted ( quoted_inner_schema )
229
290
{ :custom , { :{} , c , [ Validators.Array , :validate , [ inner_schema | args ] ] } }
230
291
end )
292
+ |> then (
293
+ & { & 1 ,
294
+ quote do
295
+ list ( unquote ( inner_type ) )
296
+ end }
297
+ )
231
298
end
232
299
233
300
defp field_to_schema ( % { type: "blob" } = field , _nsid ) do
234
301
field
235
302
|> Map . take ( [ :accept , :maxSize ] )
236
303
|> Enum . map ( fn { k , v } -> { Recase . to_snake ( k ) , v } end )
237
304
|> Validators . blob ( )
238
- |> then ( & Macro . escape / 1 )
305
+ |> then (
306
+ & { Macro . escape ( & 1 ) ,
307
+ quote do
308
+ Validators . blob ( )
309
+ end }
310
+ )
239
311
end
240
312
241
313
defp field_to_schema ( % { type: "bytes" } = field , _nsid ) do
242
314
field
243
315
|> Map . take ( [ :maxLength , :minLength ] )
244
316
|> Enum . map ( fn { k , v } -> { Recase . to_snake ( k ) , v } end )
245
317
|> Validators . bytes ( )
246
- |> then ( & Macro . escape / 1 )
318
+ |> then (
319
+ & { Macro . escape ( & 1 ) ,
320
+ quote do
321
+ Validators . bytes ( )
322
+ end }
323
+ )
247
324
end
248
325
249
326
defp field_to_schema ( % { type: "cid-link" } , _nsid ) do
250
327
Validators . cid_link ( )
251
- |> then ( & Macro . escape / 1 )
328
+ |> then (
329
+ & { Macro . escape ( & 1 ) ,
330
+ quote do
331
+ Validators . cid_link ( )
332
+ end }
333
+ )
252
334
end
253
335
254
336
# TODO: do i need to make sure these two deal with brands? Check objects in atp.tools
@@ -258,37 +340,52 @@ defmodule Atex.Lexicon do
258
340
|> Atex.NSID . expand_possible_fragment_shorthand ( ref )
259
341
|> Atex.NSID . to_atom_with_fragment ( )
260
342
261
- quote do
262
- unquote ( nsid ) . get_schema ( unquote ( fragment ) )
263
- end
343
+ { quote do
344
+ unquote ( nsid ) . get_schema ( unquote ( fragment ) )
345
+ end ,
346
+ quote do
347
+ unquote ( nsid ) . unquote ( fragment ) ( )
348
+ end }
264
349
end
265
350
266
351
defp field_to_schema ( % { type: "union" , refs: refs } , nsid ) do
267
- # refs =
268
352
refs
269
353
|> Enum . map ( fn ref ->
270
354
{ nsid , fragment } =
271
355
nsid
272
356
|> Atex.NSID . expand_possible_fragment_shorthand ( ref )
273
357
|> Atex.NSID . to_atom_with_fragment ( )
274
358
275
- quote do
276
- unquote ( nsid ) . get_schema ( unquote ( fragment ) )
277
- end
359
+ { quote do
360
+ unquote ( nsid ) . get_schema ( unquote ( fragment ) )
361
+ end ,
362
+ quote do
363
+ unquote ( nsid ) . unquote ( fragment ) ( )
364
+ end }
365
+ end )
366
+ |> Enum . reduce ( { [ ] , [ ] } , fn { quoted_schema , quoted_type } , { schemas , types } ->
367
+ { [ quoted_schema | schemas ] , [ quoted_type | types ] }
368
+ end )
369
+ |> then ( fn { schemaa , types } ->
370
+ { quote do
371
+ { :oneof , unquote ( schemaa ) }
372
+ end ,
373
+ quote do
374
+ unquote ( join_with_pipe ( types ) )
375
+ end }
376
+ |> IO . inspect ( )
278
377
end )
279
- |> then (
280
- & quote do
281
- { :oneof , unquote ( & 1 ) }
282
- end
283
- )
284
378
end
285
379
286
380
# TODO: apparently should be a data object, not a primitive?
287
381
defp field_to_schema ( % { type: "unknown" } , _nsid ) do
288
- :any
382
+ { :any ,
383
+ quote do
384
+ term ( )
385
+ end }
289
386
end
290
387
291
- defp field_to_schema ( _field_def , _nsid ) , do: nil
388
+ defp field_to_schema ( _field_def , _nsid ) , do: { nil , nil }
292
389
293
390
defp maybe_default ( schema , field ) do
294
391
if field [ :default ] != nil ,
@@ -306,4 +403,13 @@ defmodule Atex.Lexicon do
306
403
307
404
defp atomise ( x ) when is_atom ( x ) , do: x
308
405
defp atomise ( x ) when is_binary ( x ) , do: String . to_atom ( x )
406
+
407
+ defp join_with_pipe ( list ) when is_list ( list ) do
408
+ [ piped ] = do_join_with_pipe ( list )
409
+ piped
410
+ end
411
+
412
+ defp do_join_with_pipe ( [ head ] ) , do: [ head ]
413
+ defp do_join_with_pipe ( [ head | tail ] ) , do: [ { :| , [ ] , [ head | do_join_with_pipe ( tail ) ] } ]
414
+ defp do_join_with_pipe ( [ ] ) , do: [ ]
309
415
end
0 commit comments