@@ -0,0 +1,896 @@
1+module Yoga.HTTP.API.Route.OpenAPIMetadata
2+ ( class HasDescription
24+ , class HasDeprecated
28+ , class GenericEnumValues
30+ , class HasOperationMetadata
50+import Data.Either (Either(..))
51+import Data.Generic.Rep (class Generic)
52+import Data.Generic.Rep as GR
53+import Data.Maybe (Maybe(..))
54+import Data.Reflectable (class Reflectable, reflectType)
55+import Data.String.CodeUnits as SCU
56+import Data.String.Regex as Regex
57+import Data.String.Regex.Flags (noFlags)
58+import Data.Symbol (class IsSymbol, reflectSymbol)
59+import Foreign (Foreign)
60+import Prim.TypeError (class Warn, Text)
61+import Type.Proxy (Proxy(..))
62+import Unsafe.Coerce (unsafeCoerce)
63+import Yoga.HTTP.API.Path (class ParseParam, parseParam)
64+import Yoga.HTTP.API.Route.HeaderValue (class HeaderValue, parseHeader, printHeader, class HeaderValueType, headerValueType)
65+import Yoga.JSON (class ReadForeign, class WriteForeign, readImpl, writeImpl)
67+--------------------------------------------------------------------------------
68+-- Metadata Type Wrappers
69+--------------------------------------------------------------------------------
71+-- | Attach a description to a type.
72+-- | Example: Int # Description "The unique identifier for a user"
73+data Description :: Symbol -> Type -> Type
74+data Description desc a
76+-- | Attach an example value to a type.
77+-- | Example: Int # Example "123"
78+data Example :: Symbol -> Type -> Type
79+data Example exampleValue a
81+-- | Attach a format annotation to a type.
82+-- | Example: String # Format "email"
83+data Format :: Symbol -> Type -> Type
84+data Format formatStr a
86+-- | Set a minimum value constraint.
87+-- | Example: Int # Minimum 1
88+data Minimum :: Int -> Type -> Type
91+-- | Set a maximum value constraint.
92+-- | Example: Int # Maximum 100
93+data Maximum :: Int -> Type -> Type
96+-- | Set a regex pattern constraint.
97+-- | Example: String # Pattern "^[a-z]+$"
98+data Pattern :: Symbol -> Type -> Type
101+-- | Set a minimum string length constraint.
102+-- | Example: String # MinLength 1
103+data MinLength :: Int -> Type -> Type
104+data MinLength minLen a
106+-- | Set a maximum string length constraint.
107+-- | Example: String # MaxLength 255
108+data MaxLength :: Int -> Type -> Type
109+data MaxLength maxLen a
111+-- | Attach a title to a type.
112+-- | Example: String # Title "UserName"
113+data Title :: Symbol -> Type -> Type
116+-- | Mark a type as nullable.
117+-- | Example: String # Nullable
118+data Nullable :: Type -> Type
121+-- | Set a default value.
122+-- | Example: Int # Default "10"
123+data Default :: Symbol -> Type -> Type
126+-- | Mark a type as deprecated.
127+-- | Example: Int # Deprecated
128+data Deprecated :: Type -> Type
131+-- | Wrapper to use an enum type (sum type with no-argument constructors) in routes.
132+-- | The type parameter should be a Generic sum type, and enum values will be
133+-- | automatically extracted from its constructor names.
136+-- | data Status = Pending | Active | Completed
137+-- | derive instance Generic Status _
139+-- | type StatusParam = Enum Status
140+data Enum :: Type -> Type
143+--------------------------------------------------------------------------------
144+-- Metadata Extraction Typeclasses
146+-- Each Has* class matches its own wrapper and recurses through all others.
147+--------------------------------------------------------------------------------
149+-- Helper: all wrappers that a Has* class needs to recurse through.
150+-- When adding a new wrapper, add a recurse instance to every Has* class
151+-- and add the new Has* class with recurse instances for all existing wrappers.
153+class HasDescription :: Type -> Constraint
154+class HasDescription ty where
155+ description :: Proxy ty -> Maybe String
157+instance IsSymbol desc => HasDescription (Description desc a) where
158+ description _ = Just (reflectSymbol (Proxy :: Proxy desc))
159+else instance HasDescription a => HasDescription (Example ex a) where
160+ description _ = description (Proxy :: Proxy a)
161+else instance HasDescription a => HasDescription (Format fmt a) where
162+ description _ = description (Proxy :: Proxy a)
163+else instance HasDescription a => HasDescription (Minimum v a) where
164+ description _ = description (Proxy :: Proxy a)
165+else instance HasDescription a => HasDescription (Maximum v a) where
166+ description _ = description (Proxy :: Proxy a)
167+else instance HasDescription a => HasDescription (Pattern pat a) where
168+ description _ = description (Proxy :: Proxy a)
169+else instance HasDescription a => HasDescription (MinLength v a) where
170+ description _ = description (Proxy :: Proxy a)
171+else instance HasDescription a => HasDescription (MaxLength v a) where
172+ description _ = description (Proxy :: Proxy a)
173+else instance HasDescription a => HasDescription (Title t a) where
174+ description _ = description (Proxy :: Proxy a)
175+else instance HasDescription a => HasDescription (Nullable a) where
176+ description _ = description (Proxy :: Proxy a)
177+else instance HasDescription a => HasDescription (Default val a) where
178+ description _ = description (Proxy :: Proxy a)
179+else instance HasDescription a => HasDescription (Deprecated a) where
180+ description _ = description (Proxy :: Proxy a)
181+else instance HasDescription a => HasDescription (Enum a) where
182+ description _ = description (Proxy :: Proxy a)
183+else instance HasDescription ty where
184+ description _ = Nothing
186+class HasExample :: Type -> Constraint
187+class HasExample ty where
188+ example :: Proxy ty -> Maybe String
190+instance IsSymbol ex => HasExample (Example ex a) where
191+ example _ = Just (reflectSymbol (Proxy :: Proxy ex))
192+else instance HasExample a => HasExample (Description desc a) where
193+ example _ = example (Proxy :: Proxy a)
194+else instance HasExample a => HasExample (Format fmt a) where
195+ example _ = example (Proxy :: Proxy a)
196+else instance HasExample a => HasExample (Minimum v a) where
197+ example _ = example (Proxy :: Proxy a)
198+else instance HasExample a => HasExample (Maximum v a) where
199+ example _ = example (Proxy :: Proxy a)
200+else instance HasExample a => HasExample (Pattern pat a) where
201+ example _ = example (Proxy :: Proxy a)
202+else instance HasExample a => HasExample (MinLength v a) where
203+ example _ = example (Proxy :: Proxy a)
204+else instance HasExample a => HasExample (MaxLength v a) where
205+ example _ = example (Proxy :: Proxy a)
206+else instance HasExample a => HasExample (Title t a) where
207+ example _ = example (Proxy :: Proxy a)
208+else instance HasExample a => HasExample (Nullable a) where
209+ example _ = example (Proxy :: Proxy a)
210+else instance HasExample a => HasExample (Default val a) where
211+ example _ = example (Proxy :: Proxy a)
212+else instance HasExample a => HasExample (Deprecated a) where
213+ example _ = example (Proxy :: Proxy a)
214+else instance HasExample a => HasExample (Enum a) where
215+ example _ = example (Proxy :: Proxy a)
216+else instance HasExample ty where
219+class HasFormat :: Type -> Constraint
220+class HasFormat ty where
221+ format :: Proxy ty -> Maybe String
223+instance IsSymbol fmt => HasFormat (Format fmt a) where
224+ format _ = Just (reflectSymbol (Proxy :: Proxy fmt))
225+else instance HasFormat a => HasFormat (Description desc a) where
226+ format _ = format (Proxy :: Proxy a)
227+else instance HasFormat a => HasFormat (Example ex a) where
228+ format _ = format (Proxy :: Proxy a)
229+else instance HasFormat a => HasFormat (Minimum v a) where
230+ format _ = format (Proxy :: Proxy a)
231+else instance HasFormat a => HasFormat (Maximum v a) where
232+ format _ = format (Proxy :: Proxy a)
233+else instance HasFormat a => HasFormat (Pattern pat a) where
234+ format _ = format (Proxy :: Proxy a)
235+else instance HasFormat a => HasFormat (MinLength v a) where
236+ format _ = format (Proxy :: Proxy a)
237+else instance HasFormat a => HasFormat (MaxLength v a) where
238+ format _ = format (Proxy :: Proxy a)
239+else instance HasFormat a => HasFormat (Title t a) where
240+ format _ = format (Proxy :: Proxy a)
241+else instance HasFormat a => HasFormat (Nullable a) where
242+ format _ = format (Proxy :: Proxy a)
243+else instance HasFormat a => HasFormat (Default val a) where
244+ format _ = format (Proxy :: Proxy a)
245+else instance HasFormat a => HasFormat (Deprecated a) where
246+ format _ = format (Proxy :: Proxy a)
247+else instance HasFormat a => HasFormat (Enum a) where
248+ format _ = format (Proxy :: Proxy a)
249+else instance HasFormat ty where
252+class HasMinimum :: Type -> Constraint
253+class HasMinimum ty where
254+ minimum :: Proxy ty -> Maybe Int
256+instance Reflectable v Int => HasMinimum (Minimum v a) where
257+ minimum _ = Just (reflectType (Proxy :: Proxy v))
258+else instance HasMinimum a => HasMinimum (Description desc a) where
259+ minimum _ = minimum (Proxy :: Proxy a)
260+else instance HasMinimum a => HasMinimum (Example ex a) where
261+ minimum _ = minimum (Proxy :: Proxy a)
262+else instance HasMinimum a => HasMinimum (Format fmt a) where
263+ minimum _ = minimum (Proxy :: Proxy a)
264+else instance HasMinimum a => HasMinimum (Maximum v a) where
265+ minimum _ = minimum (Proxy :: Proxy a)
266+else instance HasMinimum a => HasMinimum (Pattern pat a) where
267+ minimum _ = minimum (Proxy :: Proxy a)
268+else instance HasMinimum a => HasMinimum (MinLength v a) where
269+ minimum _ = minimum (Proxy :: Proxy a)
270+else instance HasMinimum a => HasMinimum (MaxLength v a) where
271+ minimum _ = minimum (Proxy :: Proxy a)
272+else instance HasMinimum a => HasMinimum (Title t a) where
273+ minimum _ = minimum (Proxy :: Proxy a)
274+else instance HasMinimum a => HasMinimum (Nullable a) where
275+ minimum _ = minimum (Proxy :: Proxy a)
276+else instance HasMinimum a => HasMinimum (Default val a) where
277+ minimum _ = minimum (Proxy :: Proxy a)
278+else instance HasMinimum a => HasMinimum (Deprecated a) where
279+ minimum _ = minimum (Proxy :: Proxy a)
280+else instance HasMinimum a => HasMinimum (Enum a) where
281+ minimum _ = minimum (Proxy :: Proxy a)
282+else instance HasMinimum ty where
285+class HasMaximum :: Type -> Constraint
286+class HasMaximum ty where
287+ maximum :: Proxy ty -> Maybe Int
289+instance Reflectable v Int => HasMaximum (Maximum v a) where
290+ maximum _ = Just (reflectType (Proxy :: Proxy v))
291+else instance HasMaximum a => HasMaximum (Description desc a) where
292+ maximum _ = maximum (Proxy :: Proxy a)
293+else instance HasMaximum a => HasMaximum (Example ex a) where
294+ maximum _ = maximum (Proxy :: Proxy a)
295+else instance HasMaximum a => HasMaximum (Format fmt a) where
296+ maximum _ = maximum (Proxy :: Proxy a)
297+else instance HasMaximum a => HasMaximum (Minimum v a) where
298+ maximum _ = maximum (Proxy :: Proxy a)
299+else instance HasMaximum a => HasMaximum (Pattern pat a) where
300+ maximum _ = maximum (Proxy :: Proxy a)
301+else instance HasMaximum a => HasMaximum (MinLength v a) where
302+ maximum _ = maximum (Proxy :: Proxy a)
303+else instance HasMaximum a => HasMaximum (MaxLength v a) where
304+ maximum _ = maximum (Proxy :: Proxy a)
305+else instance HasMaximum a => HasMaximum (Title t a) where
306+ maximum _ = maximum (Proxy :: Proxy a)
307+else instance HasMaximum a => HasMaximum (Nullable a) where
308+ maximum _ = maximum (Proxy :: Proxy a)
309+else instance HasMaximum a => HasMaximum (Default val a) where
310+ maximum _ = maximum (Proxy :: Proxy a)
311+else instance HasMaximum a => HasMaximum (Deprecated a) where
312+ maximum _ = maximum (Proxy :: Proxy a)
313+else instance HasMaximum a => HasMaximum (Enum a) where
314+ maximum _ = maximum (Proxy :: Proxy a)
315+else instance HasMaximum ty where
318+class HasPattern :: Type -> Constraint
319+class HasPattern ty where
320+ pattern :: Proxy ty -> Maybe String
322+instance IsSymbol pat => HasPattern (Pattern pat a) where
323+ pattern _ = Just (reflectSymbol (Proxy :: Proxy pat))
324+else instance HasPattern a => HasPattern (Description desc a) where
325+ pattern _ = pattern (Proxy :: Proxy a)
326+else instance HasPattern a => HasPattern (Example ex a) where
327+ pattern _ = pattern (Proxy :: Proxy a)
328+else instance HasPattern a => HasPattern (Format fmt a) where
329+ pattern _ = pattern (Proxy :: Proxy a)
330+else instance HasPattern a => HasPattern (Minimum v a) where
331+ pattern _ = pattern (Proxy :: Proxy a)
332+else instance HasPattern a => HasPattern (Maximum v a) where
333+ pattern _ = pattern (Proxy :: Proxy a)
334+else instance HasPattern a => HasPattern (MinLength v a) where
335+ pattern _ = pattern (Proxy :: Proxy a)
336+else instance HasPattern a => HasPattern (MaxLength v a) where
337+ pattern _ = pattern (Proxy :: Proxy a)
338+else instance HasPattern a => HasPattern (Title t a) where
339+ pattern _ = pattern (Proxy :: Proxy a)
340+else instance HasPattern a => HasPattern (Nullable a) where
341+ pattern _ = pattern (Proxy :: Proxy a)
342+else instance HasPattern a => HasPattern (Default val a) where
343+ pattern _ = pattern (Proxy :: Proxy a)
344+else instance HasPattern a => HasPattern (Deprecated a) where
345+ pattern _ = pattern (Proxy :: Proxy a)
346+else instance HasPattern a => HasPattern (Enum a) where
347+ pattern _ = pattern (Proxy :: Proxy a)
348+else instance HasPattern ty where
351+class HasMinLength :: Type -> Constraint
352+class HasMinLength ty where
353+ minLength :: Proxy ty -> Maybe Int
355+instance Reflectable v Int => HasMinLength (MinLength v a) where
356+ minLength _ = Just (reflectType (Proxy :: Proxy v))
357+else instance HasMinLength a => HasMinLength (Description desc a) where
358+ minLength _ = minLength (Proxy :: Proxy a)
359+else instance HasMinLength a => HasMinLength (Example ex a) where
360+ minLength _ = minLength (Proxy :: Proxy a)
361+else instance HasMinLength a => HasMinLength (Format fmt a) where
362+ minLength _ = minLength (Proxy :: Proxy a)
363+else instance HasMinLength a => HasMinLength (Minimum v a) where
364+ minLength _ = minLength (Proxy :: Proxy a)
365+else instance HasMinLength a => HasMinLength (Maximum v a) where
366+ minLength _ = minLength (Proxy :: Proxy a)
367+else instance HasMinLength a => HasMinLength (Pattern pat a) where
368+ minLength _ = minLength (Proxy :: Proxy a)
369+else instance HasMinLength a => HasMinLength (MaxLength v a) where
370+ minLength _ = minLength (Proxy :: Proxy a)
371+else instance HasMinLength a => HasMinLength (Title t a) where
372+ minLength _ = minLength (Proxy :: Proxy a)
373+else instance HasMinLength a => HasMinLength (Nullable a) where
374+ minLength _ = minLength (Proxy :: Proxy a)
375+else instance HasMinLength a => HasMinLength (Default val a) where
376+ minLength _ = minLength (Proxy :: Proxy a)
377+else instance HasMinLength a => HasMinLength (Deprecated a) where
378+ minLength _ = minLength (Proxy :: Proxy a)
379+else instance HasMinLength a => HasMinLength (Enum a) where
380+ minLength _ = minLength (Proxy :: Proxy a)
381+else instance HasMinLength ty where
382+ minLength _ = Nothing
384+class HasMaxLength :: Type -> Constraint
385+class HasMaxLength ty where
386+ maxLength :: Proxy ty -> Maybe Int
388+instance Reflectable v Int => HasMaxLength (MaxLength v a) where
389+ maxLength _ = Just (reflectType (Proxy :: Proxy v))
390+else instance HasMaxLength a => HasMaxLength (Description desc a) where
391+ maxLength _ = maxLength (Proxy :: Proxy a)
392+else instance HasMaxLength a => HasMaxLength (Example ex a) where
393+ maxLength _ = maxLength (Proxy :: Proxy a)
394+else instance HasMaxLength a => HasMaxLength (Format fmt a) where
395+ maxLength _ = maxLength (Proxy :: Proxy a)
396+else instance HasMaxLength a => HasMaxLength (Minimum v a) where
397+ maxLength _ = maxLength (Proxy :: Proxy a)
398+else instance HasMaxLength a => HasMaxLength (Maximum v a) where
399+ maxLength _ = maxLength (Proxy :: Proxy a)
400+else instance HasMaxLength a => HasMaxLength (Pattern pat a) where
401+ maxLength _ = maxLength (Proxy :: Proxy a)
402+else instance HasMaxLength a => HasMaxLength (MinLength v a) where
403+ maxLength _ = maxLength (Proxy :: Proxy a)
404+else instance HasMaxLength a => HasMaxLength (Title t a) where
405+ maxLength _ = maxLength (Proxy :: Proxy a)
406+else instance HasMaxLength a => HasMaxLength (Nullable a) where
407+ maxLength _ = maxLength (Proxy :: Proxy a)
408+else instance HasMaxLength a => HasMaxLength (Default val a) where
409+ maxLength _ = maxLength (Proxy :: Proxy a)
410+else instance HasMaxLength a => HasMaxLength (Deprecated a) where
411+ maxLength _ = maxLength (Proxy :: Proxy a)
412+else instance HasMaxLength a => HasMaxLength (Enum a) where
413+ maxLength _ = maxLength (Proxy :: Proxy a)
414+else instance HasMaxLength ty where
415+ maxLength _ = Nothing
417+class HasTitle :: Type -> Constraint
418+class HasTitle ty where
419+ title :: Proxy ty -> Maybe String
421+instance IsSymbol t => HasTitle (Title t a) where
422+ title _ = Just (reflectSymbol (Proxy :: Proxy t))
423+else instance HasTitle a => HasTitle (Description desc a) where
424+ title _ = title (Proxy :: Proxy a)
425+else instance HasTitle a => HasTitle (Example ex a) where
426+ title _ = title (Proxy :: Proxy a)
427+else instance HasTitle a => HasTitle (Format fmt a) where
428+ title _ = title (Proxy :: Proxy a)
429+else instance HasTitle a => HasTitle (Minimum v a) where
430+ title _ = title (Proxy :: Proxy a)
431+else instance HasTitle a => HasTitle (Maximum v a) where
432+ title _ = title (Proxy :: Proxy a)
433+else instance HasTitle a => HasTitle (Pattern pat a) where
434+ title _ = title (Proxy :: Proxy a)
435+else instance HasTitle a => HasTitle (MinLength v a) where
436+ title _ = title (Proxy :: Proxy a)
437+else instance HasTitle a => HasTitle (MaxLength v a) where
438+ title _ = title (Proxy :: Proxy a)
439+else instance HasTitle a => HasTitle (Nullable a) where
440+ title _ = title (Proxy :: Proxy a)
441+else instance HasTitle a => HasTitle (Default val a) where
442+ title _ = title (Proxy :: Proxy a)
443+else instance HasTitle a => HasTitle (Deprecated a) where
444+ title _ = title (Proxy :: Proxy a)
445+else instance HasTitle a => HasTitle (Enum a) where
446+ title _ = title (Proxy :: Proxy a)
447+else instance HasTitle ty where
450+class HasNullable :: Type -> Constraint
451+class HasNullable ty where
452+ nullable :: Proxy ty -> Boolean
454+instance HasNullable (Nullable a) where
456+else instance HasNullable a => HasNullable (Description desc a) where
457+ nullable _ = nullable (Proxy :: Proxy a)
458+else instance HasNullable a => HasNullable (Example ex a) where
459+ nullable _ = nullable (Proxy :: Proxy a)
460+else instance HasNullable a => HasNullable (Format fmt a) where
461+ nullable _ = nullable (Proxy :: Proxy a)
462+else instance HasNullable a => HasNullable (Minimum v a) where
463+ nullable _ = nullable (Proxy :: Proxy a)
464+else instance HasNullable a => HasNullable (Maximum v a) where
465+ nullable _ = nullable (Proxy :: Proxy a)
466+else instance HasNullable a => HasNullable (Pattern pat a) where
467+ nullable _ = nullable (Proxy :: Proxy a)
468+else instance HasNullable a => HasNullable (MinLength v a) where
469+ nullable _ = nullable (Proxy :: Proxy a)
470+else instance HasNullable a => HasNullable (MaxLength v a) where
471+ nullable _ = nullable (Proxy :: Proxy a)
472+else instance HasNullable a => HasNullable (Title t a) where
473+ nullable _ = nullable (Proxy :: Proxy a)
474+else instance HasNullable a => HasNullable (Default val a) where
475+ nullable _ = nullable (Proxy :: Proxy a)
476+else instance HasNullable a => HasNullable (Deprecated a) where
477+ nullable _ = nullable (Proxy :: Proxy a)
478+else instance HasNullable a => HasNullable (Enum a) where
479+ nullable _ = nullable (Proxy :: Proxy a)
480+else instance HasNullable ty where
483+class HasDefault :: Type -> Constraint
484+class HasDefault ty where
485+ default :: Proxy ty -> Maybe String
487+instance IsSymbol val => HasDefault (Default val a) where
488+ default _ = Just (reflectSymbol (Proxy :: Proxy val))
489+else instance HasDefault a => HasDefault (Description desc a) where
490+ default _ = default (Proxy :: Proxy a)
491+else instance HasDefault a => HasDefault (Example ex a) where
492+ default _ = default (Proxy :: Proxy a)
493+else instance HasDefault a => HasDefault (Format fmt a) where
494+ default _ = default (Proxy :: Proxy a)
495+else instance HasDefault a => HasDefault (Minimum v a) where
496+ default _ = default (Proxy :: Proxy a)
497+else instance HasDefault a => HasDefault (Maximum v a) where
498+ default _ = default (Proxy :: Proxy a)
499+else instance HasDefault a => HasDefault (Pattern pat a) where
500+ default _ = default (Proxy :: Proxy a)
501+else instance HasDefault a => HasDefault (MinLength v a) where
502+ default _ = default (Proxy :: Proxy a)
503+else instance HasDefault a => HasDefault (MaxLength v a) where
504+ default _ = default (Proxy :: Proxy a)
505+else instance HasDefault a => HasDefault (Title t a) where
506+ default _ = default (Proxy :: Proxy a)
507+else instance HasDefault a => HasDefault (Nullable a) where
508+ default _ = default (Proxy :: Proxy a)
509+else instance HasDefault a => HasDefault (Deprecated a) where
510+ default _ = default (Proxy :: Proxy a)
511+else instance HasDefault a => HasDefault (Enum a) where
512+ default _ = default (Proxy :: Proxy a)
513+else instance HasDefault ty where
516+class HasDeprecated :: Type -> Constraint
517+class HasDeprecated ty where
518+ deprecated :: Proxy ty -> Boolean
520+instance HasDeprecated (Deprecated a) where
522+else instance HasDeprecated a => HasDeprecated (Description desc a) where
523+ deprecated _ = deprecated (Proxy :: Proxy a)
524+else instance HasDeprecated a => HasDeprecated (Example ex a) where
525+ deprecated _ = deprecated (Proxy :: Proxy a)
526+else instance HasDeprecated a => HasDeprecated (Format fmt a) where
527+ deprecated _ = deprecated (Proxy :: Proxy a)
528+else instance HasDeprecated a => HasDeprecated (Minimum v a) where
529+ deprecated _ = deprecated (Proxy :: Proxy a)
530+else instance HasDeprecated a => HasDeprecated (Maximum v a) where
531+ deprecated _ = deprecated (Proxy :: Proxy a)
532+else instance HasDeprecated a => HasDeprecated (Pattern pat a) where
533+ deprecated _ = deprecated (Proxy :: Proxy a)
534+else instance HasDeprecated a => HasDeprecated (MinLength v a) where
535+ deprecated _ = deprecated (Proxy :: Proxy a)
536+else instance HasDeprecated a => HasDeprecated (MaxLength v a) where
537+ deprecated _ = deprecated (Proxy :: Proxy a)
538+else instance HasDeprecated a => HasDeprecated (Title t a) where
539+ deprecated _ = deprecated (Proxy :: Proxy a)
540+else instance HasDeprecated a => HasDeprecated (Nullable a) where
541+ deprecated _ = deprecated (Proxy :: Proxy a)
542+else instance HasDeprecated a => HasDeprecated (Default val a) where
543+ deprecated _ = deprecated (Proxy :: Proxy a)
544+else instance HasDeprecated a => HasDeprecated (Enum a) where
545+ deprecated _ = deprecated (Proxy :: Proxy a)
546+else instance HasDeprecated ty where
547+ deprecated _ = false
549+class HasEnum :: Type -> Constraint
550+class HasEnum ty where
551+ enum :: Proxy ty -> Maybe (Array String)
553+-- | Extract enum values from a Generic sum type representation.
554+-- | Walks through GR.Sum constructors and collects constructor names.
555+class GenericEnumValues :: Type -> Constraint
556+class GenericEnumValues rep where
557+ genericEnumValues :: Proxy rep -> Array String
559+-- Walk sum types (left and right branches)
560+instance (GenericEnumValues a, GenericEnumValues b) => GenericEnumValues (GR.Sum a b) where
561+ genericEnumValues _ =
562+ genericEnumValues (Proxy :: Proxy a) <> genericEnumValues (Proxy :: Proxy b)
564+-- Extract constructor name from no-argument constructors
565+instance IsSymbol name => GenericEnumValues (GR.Constructor name GR.NoArguments) where
566+ genericEnumValues _ = [ reflectSymbol (Proxy :: Proxy name) ]
568+-- Main instance: extract enum values from a Generic type wrapped in Enum
569+instance (Generic a rep, GenericEnumValues rep) => HasEnum (Enum a) where
570+ enum _ = Just (genericEnumValues (Proxy :: Proxy rep))
571+else instance HasEnum a => HasEnum (Description desc a) where
572+ enum _ = enum (Proxy :: Proxy a)
573+else instance HasEnum a => HasEnum (Example ex a) where
574+ enum _ = enum (Proxy :: Proxy a)
575+else instance HasEnum a => HasEnum (Format fmt a) where
576+ enum _ = enum (Proxy :: Proxy a)
577+else instance HasEnum a => HasEnum (Minimum v a) where
578+ enum _ = enum (Proxy :: Proxy a)
579+else instance HasEnum a => HasEnum (Maximum v a) where
580+ enum _ = enum (Proxy :: Proxy a)
581+else instance HasEnum a => HasEnum (Pattern pat a) where
582+ enum _ = enum (Proxy :: Proxy a)
583+else instance HasEnum a => HasEnum (MinLength v a) where
584+ enum _ = enum (Proxy :: Proxy a)
585+else instance HasEnum a => HasEnum (MaxLength v a) where
586+ enum _ = enum (Proxy :: Proxy a)
587+else instance HasEnum a => HasEnum (Title t a) where
588+ enum _ = enum (Proxy :: Proxy a)
589+else instance HasEnum a => HasEnum (Nullable a) where
590+ enum _ = enum (Proxy :: Proxy a)
591+else instance HasEnum a => HasEnum (Default val a) where
592+ enum _ = enum (Proxy :: Proxy a)
593+else instance HasEnum a => HasEnum (Deprecated a) where
594+ enum _ = enum (Proxy :: Proxy a)
595+else instance HasEnum ty where
598+--------------------------------------------------------------------------------
599+-- Operation-Level Metadata
600+--------------------------------------------------------------------------------
602+type OperationMetadata =
603+ { summary :: Maybe String
604+ , description :: Maybe String
605+ , operationId :: Maybe String
606+ , tags :: Array String
607+ , deprecated :: Boolean
610+class HasOperationMetadata :: Type -> Constraint
611+class HasOperationMetadata route where
612+ operationMetadata :: Proxy route -> OperationMetadata
614+instance (Warn (Text "Using default operation metadata")) => HasOperationMetadata route where
615+ operationMetadata _ =
617+ , description: Nothing
618+ , operationId: Nothing
623+--------------------------------------------------------------------------------
624+-- Metadata Wrapper Transparency (Runtime)
626+-- All wrappers are phantom types — transparent at runtime via unsafeCoerce.
627+--------------------------------------------------------------------------------
629+-- HeaderValue instances
630+instance HeaderValue a => HeaderValue (Description desc a) where
631+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
632+ printHeader x = printHeader (unsafeCoerce x :: a)
634+instance HeaderValue a => HeaderValue (Example ex a) where
635+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
636+ printHeader x = printHeader (unsafeCoerce x :: a)
638+instance HeaderValue a => HeaderValue (Format fmt a) where
639+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
640+ printHeader x = printHeader (unsafeCoerce x :: a)
642+instance (Reflectable v Int, HeaderValue a) => HeaderValue (Minimum v a) where
643+ parseHeader s = case (unsafeCoerce :: Either String a -> Either String Int) (parseHeader s :: Either String a) of
644+ Left err -> Left err
647+ minVal = reflectType (Proxy :: Proxy v)
649+ if val < minVal then Left ("Value " <> show val <> " is less than minimum " <> show minVal)
650+ else Right (unsafeCoerce val)
651+ printHeader x = printHeader (unsafeCoerce x :: a)
653+instance (Reflectable v Int, HeaderValue a) => HeaderValue (Maximum v a) where
654+ parseHeader s = case (unsafeCoerce :: Either String a -> Either String Int) (parseHeader s :: Either String a) of
655+ Left err -> Left err
658+ maxVal = reflectType (Proxy :: Proxy v)
660+ if val > maxVal then Left ("Value " <> show val <> " exceeds maximum " <> show maxVal)
661+ else Right (unsafeCoerce val)
662+ printHeader x = printHeader (unsafeCoerce x :: a)
664+instance (IsSymbol pat, HeaderValue a) => HeaderValue (Pattern pat a) where
665+ parseHeader s = case Regex.regex (reflectSymbol (Proxy :: Proxy pat)) noFlags of
666+ Left err -> Left ("Invalid regex pattern: " <> err)
668+ if Regex.test re s then unsafeCoerce (parseHeader s :: Either String a)
669+ else Left ("Value '" <> s <> "' does not match pattern: " <> reflectSymbol (Proxy :: Proxy pat))
670+ printHeader x = printHeader (unsafeCoerce x :: a)
672+instance (Reflectable v Int, HeaderValue a) => HeaderValue (MinLength v a) where
675+ minLen = reflectType (Proxy :: Proxy v)
677+ if SCU.length s < minLen then Left ("String length " <> show (SCU.length s) <> " is less than minimum " <> show minLen)
678+ else unsafeCoerce (parseHeader s :: Either String a)
679+ printHeader x = printHeader (unsafeCoerce x :: a)
681+instance (Reflectable v Int, HeaderValue a) => HeaderValue (MaxLength v a) where
684+ maxLen = reflectType (Proxy :: Proxy v)
686+ if SCU.length s > maxLen then Left ("String length " <> show (SCU.length s) <> " exceeds maximum " <> show maxLen)
687+ else unsafeCoerce (parseHeader s :: Either String a)
688+ printHeader x = printHeader (unsafeCoerce x :: a)
690+instance HeaderValue a => HeaderValue (Title t a) where
691+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
692+ printHeader x = printHeader (unsafeCoerce x :: a)
694+instance HeaderValue a => HeaderValue (Nullable a) where
695+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
696+ printHeader x = printHeader (unsafeCoerce x :: a)
698+instance HeaderValue a => HeaderValue (Default val a) where
699+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
700+ printHeader x = printHeader (unsafeCoerce x :: a)
702+instance HeaderValue a => HeaderValue (Deprecated a) where
703+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
704+ printHeader x = printHeader (unsafeCoerce x :: a)
706+instance HeaderValue a => HeaderValue (Enum a) where
707+ parseHeader s = unsafeCoerce (parseHeader s :: Either String a)
708+ printHeader x = printHeader (unsafeCoerce x :: a)
710+-- HeaderValueType instances
711+instance HeaderValueType a => HeaderValueType (Description desc a) where
712+ headerValueType _ = headerValueType (Proxy :: Proxy a)
714+instance HeaderValueType a => HeaderValueType (Example ex a) where
715+ headerValueType _ = headerValueType (Proxy :: Proxy a)
717+instance HeaderValueType a => HeaderValueType (Format fmt a) where
718+ headerValueType _ = headerValueType (Proxy :: Proxy a)
720+instance HeaderValueType a => HeaderValueType (Minimum v a) where
721+ headerValueType _ = headerValueType (Proxy :: Proxy a)
723+instance HeaderValueType a => HeaderValueType (Maximum v a) where
724+ headerValueType _ = headerValueType (Proxy :: Proxy a)
726+instance HeaderValueType a => HeaderValueType (Pattern pat a) where
727+ headerValueType _ = headerValueType (Proxy :: Proxy a)
729+instance HeaderValueType a => HeaderValueType (MinLength v a) where
730+ headerValueType _ = headerValueType (Proxy :: Proxy a)
732+instance HeaderValueType a => HeaderValueType (MaxLength v a) where
733+ headerValueType _ = headerValueType (Proxy :: Proxy a)
735+instance HeaderValueType a => HeaderValueType (Title t a) where
736+ headerValueType _ = headerValueType (Proxy :: Proxy a)
738+instance HeaderValueType a => HeaderValueType (Nullable a) where
739+ headerValueType _ = headerValueType (Proxy :: Proxy a)
741+instance HeaderValueType a => HeaderValueType (Default val a) where
742+ headerValueType _ = headerValueType (Proxy :: Proxy a)
744+instance HeaderValueType a => HeaderValueType (Deprecated a) where
745+ headerValueType _ = headerValueType (Proxy :: Proxy a)
747+instance HeaderValueType a => HeaderValueType (Enum a) where
748+ headerValueType _ = headerValueType (Proxy :: Proxy a)
750+-- ParseParam instances
751+instance ParseParam a => ParseParam (Description desc a) where
752+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
754+instance ParseParam a => ParseParam (Example ex a) where
755+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
757+instance ParseParam a => ParseParam (Format fmt a) where
758+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
760+instance (Reflectable v Int, ParseParam a) => ParseParam (Minimum v a) where
761+ parseParam s = case (unsafeCoerce :: Either String a -> Either String Int) (parseParam s :: Either String a) of
762+ Left err -> Left err
765+ minVal = reflectType (Proxy :: Proxy v)
767+ if val < minVal then Left ("Value " <> show val <> " is less than minimum " <> show minVal)
768+ else Right (unsafeCoerce val)
770+instance (Reflectable v Int, ParseParam a) => ParseParam (Maximum v a) where
771+ parseParam s = case (unsafeCoerce :: Either String a -> Either String Int) (parseParam s :: Either String a) of
772+ Left err -> Left err
775+ maxVal = reflectType (Proxy :: Proxy v)
777+ if val > maxVal then Left ("Value " <> show val <> " exceeds maximum " <> show maxVal)
778+ else Right (unsafeCoerce val)
780+instance (IsSymbol pat, ParseParam a) => ParseParam (Pattern pat a) where
781+ parseParam s = case Regex.regex (reflectSymbol (Proxy :: Proxy pat)) noFlags of
782+ Left err -> Left ("Invalid regex pattern: " <> err)
784+ if Regex.test re s then unsafeCoerce (parseParam s :: Either String a)
785+ else Left ("Value '" <> s <> "' does not match pattern: " <> reflectSymbol (Proxy :: Proxy pat))
787+instance (Reflectable v Int, ParseParam a) => ParseParam (MinLength v a) where
790+ minLen = reflectType (Proxy :: Proxy v)
792+ if SCU.length s < minLen then Left ("String length " <> show (SCU.length s) <> " is less than minimum " <> show minLen)
793+ else unsafeCoerce (parseParam s :: Either String a)
795+instance (Reflectable v Int, ParseParam a) => ParseParam (MaxLength v a) where
798+ maxLen = reflectType (Proxy :: Proxy v)
800+ if SCU.length s > maxLen then Left ("String length " <> show (SCU.length s) <> " exceeds maximum " <> show maxLen)
801+ else unsafeCoerce (parseParam s :: Either String a)
803+instance ParseParam a => ParseParam (Title t a) where
804+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
806+instance ParseParam a => ParseParam (Nullable a) where
807+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
809+instance ParseParam a => ParseParam (Default val a) where
810+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
812+instance ParseParam a => ParseParam (Deprecated a) where
813+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
815+instance ParseParam a => ParseParam (Enum a) where
816+ parseParam s = unsafeCoerce (parseParam s :: Either String a)
818+-- WriteForeign instances
819+instance WriteForeign a => WriteForeign (Description desc a) where
820+ writeImpl x = writeImpl (unsafeCoerce x :: a)
822+instance WriteForeign a => WriteForeign (Example ex a) where
823+ writeImpl x = writeImpl (unsafeCoerce x :: a)
825+instance WriteForeign a => WriteForeign (Format fmt a) where
826+ writeImpl x = writeImpl (unsafeCoerce x :: a)
828+instance WriteForeign a => WriteForeign (Minimum v a) where
829+ writeImpl x = writeImpl (unsafeCoerce x :: a)
831+instance WriteForeign a => WriteForeign (Maximum v a) where
832+ writeImpl x = writeImpl (unsafeCoerce x :: a)
834+instance WriteForeign a => WriteForeign (Pattern pat a) where
835+ writeImpl x = writeImpl (unsafeCoerce x :: a)
837+instance WriteForeign a => WriteForeign (MinLength v a) where
838+ writeImpl x = writeImpl (unsafeCoerce x :: a)
840+instance WriteForeign a => WriteForeign (MaxLength v a) where
841+ writeImpl x = writeImpl (unsafeCoerce x :: a)
843+instance WriteForeign a => WriteForeign (Title t a) where
844+ writeImpl x = writeImpl (unsafeCoerce x :: a)
846+instance WriteForeign a => WriteForeign (Nullable a) where
847+ writeImpl x = writeImpl (unsafeCoerce x :: a)
849+instance WriteForeign a => WriteForeign (Default val a) where
850+ writeImpl x = writeImpl (unsafeCoerce x :: a)
852+instance WriteForeign a => WriteForeign (Deprecated a) where
853+ writeImpl x = writeImpl (unsafeCoerce x :: a)
855+instance WriteForeign a => WriteForeign (Enum a) where
856+ writeImpl x = writeImpl (unsafeCoerce x :: a)
858+-- ReadForeign instances
859+instance ReadForeign a => ReadForeign (Description desc a) where
860+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
862+instance ReadForeign a => ReadForeign (Example ex a) where
863+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
865+instance ReadForeign a => ReadForeign (Format fmt a) where
866+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
868+instance ReadForeign a => ReadForeign (Minimum v a) where
869+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
871+instance ReadForeign a => ReadForeign (Maximum v a) where
872+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
874+instance ReadForeign a => ReadForeign (Pattern pat a) where
875+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
877+instance ReadForeign a => ReadForeign (MinLength v a) where
878+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
880+instance ReadForeign a => ReadForeign (MaxLength v a) where
881+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
883+instance ReadForeign a => ReadForeign (Title t a) where
884+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
886+instance ReadForeign a => ReadForeign (Nullable a) where
887+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
889+instance ReadForeign a => ReadForeign (Default val a) where
890+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
892+instance ReadForeign a => ReadForeign (Deprecated a) where
893+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)
895+instance ReadForeign a => ReadForeign (Enum a) where
896+ readImpl = unsafeCoerce (readImpl :: Foreign -> _ a)