1{-# LANGUAGE OverloadedStrings #-}
2module Generate.JavaScript.Expression
14import qualified Data.IntMap as IntMap
15import qualified Data.List as List
16import qualified Data.Map as Map
17import qualified Data.Text.Encoding as Text
19import qualified AST.Canonical as Can
20import qualified AST.Optimized as Opt
21import qualified AST.Module.Name as ModuleName
22import qualified Data.Index as Index
23import qualified Elm.Compiler.Type as Type
24import qualified Elm.Compiler.Type.Extract as Extract
25import qualified Elm.Interface as I
26import qualified Elm.Name as N
27import qualified Elm.Package as Pkg
28import qualified Elm.Compiler.Version as Version
29import qualified Generate.JavaScript.Builder as JS
30import qualified Generate.JavaScript.Name as Name
31import qualified Json.Encode as Encode
32import qualified Optimize.DecisionTree as DT
33import qualified Reporting.Region as R
47generateJsExpr :: Mode -> Opt.Expr -> JS.Expr
48generateJsExpr mode expression =
49 codeToExpr (generate mode expression)
52generate :: Mode -> Opt.Expr -> Code
53generate mode expression =
59 JS.Call toChar [ JS.String (Text.encodeUtf8Builder char) ]
62 JS.String (Text.encodeUtf8Builder char)
65 JsExpr $ JS.String (Text.encodeUtf8Builder string)
71 JsExpr $ JS.Float float
74 JsExpr $ JS.Ref (Name.fromLocal name)
76 Opt.VarGlobal (Opt.Global home name) ->
77 JsExpr $ JS.Ref (Name.fromGlobal home name)
79 Opt.VarEnum (Opt.Global home name) index ->
82 JsExpr $ JS.Ref (Name.fromGlobal home name)
85 JsExpr $ JS.Int (Index.toMachine index)
87 Opt.VarBox (Opt.Global home name) ->
90 Name.Debug _ -> Name.fromGlobal home name
91 Name.Prod _ _ -> Name.fromGlobal ModuleName.basics N.identity
93 Opt.VarCycle home name ->
94 JsExpr $ JS.Call (JS.Ref (Name.fromCycle home name)) []
96 Opt.VarDebug name home region unhandledValueName ->
97 JsExpr $ generateDebug name home region unhandledValueName
99 Opt.VarKernel home name ->
100 JsExpr $ JS.Ref (Name.fromKernel home name)
105 (JS.Ref (Name.fromKernel N.list "fromArray"))
106 [ JS.Array $ map (generateJsExpr mode) entries
109 Opt.Function args body ->
110 generateFunction (map Name.fromLocal args) (generate mode body)
112 Opt.Call func args ->
113 JsExpr $ generateCall mode func args
115 Opt.TailCall name args ->
116 JsBlock $ generateTailCall mode name args
118 Opt.If branches final ->
119 generateIf mode branches final
123 generateDef mode def : codeToStmtList (generate mode body)
125 Opt.Destruct (Opt.Destructor name path) body ->
127 pathExpr = generatePath mode path
128 pathDef = JS.Var [ (Name.fromLocal name, Just pathExpr) ]
130 JsBlock $ pathDef : codeToStmtList (generate mode body)
132 Opt.Case label root decider jumps ->
133 JsBlock $ generateCase mode label root decider jumps
135 Opt.Accessor field ->
136 JsExpr $ JS.Function Nothing [Name.dollar]
138 JS.Access (JS.Ref Name.dollar) (Name.fromField mode field)
141 Opt.Access record field ->
142 JsExpr $ JS.Access (generateJsExpr mode record) (Name.fromField mode field)
144 Opt.Update record fields ->
146 JS.Call (JS.Ref (Name.fromKernel N.utils "update"))
147 [ generateJsExpr mode record
148 , generateRecord mode fields
152 JsExpr $ generateRecord mode fields
157 JsExpr $ JS.Ref (Name.fromKernel N.utils "Tuple0")
162 Opt.Tuple a b maybeC ->
166 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple2"))
167 [ generateJsExpr mode a
168 , generateJsExpr mode b
172 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple3"))
173 [ generateJsExpr mode a
174 , generateJsExpr mode b
175 , generateJsExpr mode c
179 let string = JS.String (Text.encodeUtf8Builder src) in
180 JsExpr $ JS.Object [ ( Name.fromLocal "src", string ) ]
192codeToExpr :: Code -> JS.Expr
198 JsBlock [ JS.Return (Just expr) ] ->
202 JS.Call (JS.Function Nothing [] stmts) []
205codeToStmtList :: Code -> [JS.Stmt]
209 [ JS.Return (Just expr) ]
215codeToStmt :: Code -> JS.Stmt
219 JS.Return (Just expr)
232{-# NOINLINE toChar #-}
235 JS.Ref (Name.fromKernel N.utils "chr")
242generateCtor :: Mode -> N.Name -> Index.ZeroBased -> Int -> Code
243generateCtor mode name index arity =
246 Index.indexedMap (\i _ -> Name.fromIndex i) [1 .. arity]
250 Name.Debug _ -> JS.String (N.toBuilder name)
251 Name.Prod _ _ -> JS.Int (Index.toMachine index)
253 generateFunction argNames $ JsExpr $ JS.Object $
254 (Name.dollar, ctorTag) : map (\n -> (n, JS.Ref n)) argNames
261generateRecord :: Mode -> Map.Map N.Name Opt.Expr -> JS.Expr
262generateRecord mode fields =
264 toPair (field, value) =
265 (Name.fromField mode field, generateJsExpr mode value)
267 JS.Object (map toPair (Map.toList fields))
274generateDebug :: N.Name -> ModuleName.Canonical -> R.Region -> Maybe N.Name -> JS.Expr
275generateDebug name (ModuleName.Canonical _ home) region unhandledValueName =
276 if name /= "crash" then
277 JS.Ref (Name.fromGlobal ModuleName.debug name)
279 case unhandledValueName of
281 JS.Call (JS.Ref (Name.fromKernel N.utils "crash")) $
282 [ JS.String (N.toBuilder home)
283 , regionToJsExpr region
287 JS.Call (JS.Ref (Name.fromKernel N.utils "crashCase")) $
288 [ JS.String (N.toBuilder home)
289 , regionToJsExpr region
290 , JS.Ref (Name.fromLocal valueName)
294regionToJsExpr :: R.Region -> JS.Expr
295regionToJsExpr (R.Region start end) =
297 [ ( Name.fromLocal "start", positionToJsExpr start )
298 , ( Name.fromLocal "end", positionToJsExpr end )
302positionToJsExpr :: R.Position -> JS.Expr
303positionToJsExpr (R.Position line column) =
305 [ ( Name.fromLocal "line", JS.Int line )
306 , ( Name.fromLocal "column", JS.Int column )
314generateFunction :: [Name.Name] -> Code -> Code
315generateFunction args body =
316 case IntMap.lookup (length args) funcHelpers of
320 [ JS.Function Nothing args $
327 JsExpr $ JS.Function Nothing [arg] $
330 foldr addArg body args
333{-# NOINLINE funcHelpers #-}
334funcHelpers :: IntMap.IntMap JS.Expr
337 [ (2, JS.Ref (Name.fromLocal "F2"))
338 , (3, JS.Ref (Name.fromLocal "F3"))
339 , (4, JS.Ref (Name.fromLocal "F4"))
340 , (5, JS.Ref (Name.fromLocal "F5"))
341 , (6, JS.Ref (Name.fromLocal "F6"))
342 , (7, JS.Ref (Name.fromLocal "F7"))
343 , (8, JS.Ref (Name.fromLocal "F8"))
344 , (9, JS.Ref (Name.fromLocal "F9"))
352generateCall :: Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
353generateCall mode func args =
355 Opt.VarGlobal global@(Opt.Global (ModuleName.Canonical pkg _) _) | pkg == Pkg.core ->
356 generateCoreCall mode global args
361 generateCallHelp mode func args
366 generateJsExpr mode arg
369 generateCallHelp mode func args
372 generateCallHelp mode func args
375generateCallHelp :: Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
376generateCallHelp mode func args =
378 (generateJsExpr mode func)
379 (map (generateJsExpr mode) args)
382generateGlobalCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
383generateGlobalCall home name args =
384 generateNormalCall (JS.Ref (Name.fromGlobal home name)) args
387generateNormalCall :: JS.Expr -> [JS.Expr] -> JS.Expr
388generateNormalCall func args =
389 case IntMap.lookup (length args) callHelpers of
391 JS.Call helper (func:args)
394 List.foldl' (\f a -> JS.Call f [a]) func args
397{-# NOINLINE callHelpers #-}
398callHelpers :: IntMap.IntMap JS.Expr
401 [ (2, JS.Ref (Name.fromLocal "A2"))
402 , (3, JS.Ref (Name.fromLocal "A3"))
403 , (4, JS.Ref (Name.fromLocal "A4"))
404 , (5, JS.Ref (Name.fromLocal "A5"))
405 , (6, JS.Ref (Name.fromLocal "A6"))
406 , (7, JS.Ref (Name.fromLocal "A7"))
407 , (8, JS.Ref (Name.fromLocal "A8"))
408 , (9, JS.Ref (Name.fromLocal "A9"))
416generateCoreCall :: Mode -> Opt.Global -> [Opt.Expr] -> JS.Expr
417generateCoreCall mode (Opt.Global home@(ModuleName.Canonical _ moduleName) name) args =
418 if moduleName == N.basics then
419 generateBasicsCall mode home name args
421 else if moduleName == N.bitwise then
422 generateBitwiseCall home name (map (generateJsExpr mode) args)
424 else if moduleName == N.tuple then
425 generateTupleCall home name (map (generateJsExpr mode) args)
427 else if moduleName == N.jsArray then
428 generateJsArrayCall home name (map (generateJsExpr mode) args)
431 generateGlobalCall home name (map (generateJsExpr mode) args)
434generateTupleCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
435generateTupleCall home name args =
439 "first" -> JS.Access value (Name.fromLocal "a")
440 "second" -> JS.Access value (Name.fromLocal "b")
441 _ -> generateGlobalCall home name args
444 generateGlobalCall home name args
447generateJsArrayCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
448generateJsArrayCall home name args =
450 [entry] | name == "singleton" -> JS.Array [entry]
451 [index, array] | name == "unsafeGet" -> JS.Index array index
452 _ -> generateGlobalCall home name args
455generateBitwiseCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
456generateBitwiseCall home name args =
460 "complement" -> JS.Prefix JS.PrefixBNot arg
461 _ -> generateGlobalCall home name args
465 "and" -> JS.Infix JS.OpBAnd left right
466 "or" -> JS.Infix JS.OpBOr left right
467 "xor" -> JS.Infix JS.OpBXor left right
468 "shiftLeftBy" -> JS.Infix JS.OpLShift right left
469 "shiftRightBy" -> JS.Infix JS.OpSpRShift right left
470 "shiftRightZfBy" -> JS.Infix JS.OpZfRShift right left
471 _ -> generateGlobalCall home name args
474 generateGlobalCall home name args
477generateBasicsCall :: Mode -> ModuleName.Canonical -> N.Name -> [Opt.Expr] -> JS.Expr
478generateBasicsCall mode home name args =
481 let arg = generateJsExpr mode elmArg in
483 "not" -> JS.Prefix JS.PrefixLNot arg
485 "truncate" -> JS.Infix JS.OpBOr arg (JS.Int 0)
486 _ -> generateGlobalCall home name [arg]
488 [elmLeft, elmRight] ->
490 "composeL" -> decomposeL mode elmLeft [elmRight]
491 "composeR" -> decomposeR mode [elmLeft] elmRight
492 "append" -> append mode elmLeft elmRight
493 "apL" -> generateJsExpr mode $ apply elmLeft elmRight
494 "apR" -> generateJsExpr mode $ apply elmRight elmLeft
497 left = generateJsExpr mode elmLeft
498 right = generateJsExpr mode elmRight
501 "add" -> JS.Infix JS.OpAdd left right
502 "sub" -> JS.Infix JS.OpSub left right
503 "mul" -> JS.Infix JS.OpMul left right
504 "fdiv" -> JS.Infix JS.OpDiv left right
505 "idiv" -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv left right) (JS.Int 0)
506 "eq" -> equal left right
507 "neq" -> notEqual left right
508 "lt" -> cmp JS.OpLT JS.OpLT 0 left right
509 "gt" -> cmp JS.OpGT JS.OpGT 0 left right
510 "le" -> cmp JS.OpLEq JS.OpLT 1 left right
511 "ge" -> cmp JS.OpGEq JS.OpGT (-1) left right
512 "or" -> JS.Infix JS.OpLOr left right
513 "and" -> JS.Infix JS.OpLAnd left right
514 "xor" -> JS.Infix JS.OpStrictNEq left right
515 _ -> generateGlobalCall home name [left, right]
518 generateGlobalCall home name (map (generateJsExpr mode) args)
521equal :: JS.Expr -> JS.Expr -> JS.Expr
523 if isLiteral left || isLiteral right then
526 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
529notEqual :: JS.Expr -> JS.Expr -> JS.Expr
531 if isLiteral left || isLiteral right then
534 JS.Prefix JS.PrefixLNot $
535 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
538cmp :: JS.InfixOp -> JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
539cmp idealOp backupOp backupInt left right =
540 if isLiteral left || isLiteral right then
541 JS.Infix idealOp left right
544 (JS.Call (JS.Ref (Name.fromKernel N.utils "cmp")) [left, right])
548isLiteral :: JS.Expr -> Bool
567decomposeL :: Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
568decomposeL mode expr funcs =
570 Opt.Call (Opt.VarGlobal (Opt.Global home "composeL")) [left, func]
571 | home == ModuleName.basics ->
572 decomposeL mode left (func:funcs)
575 generateJsExpr mode $
576 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
579decomposeR :: Mode -> [Opt.Expr] -> Opt.Expr -> JS.Expr
580decomposeR mode funcs expr =
582 Opt.Call (Opt.VarGlobal (Opt.Global home "composeR")) [func, right]
583 | home == ModuleName.basics ->
584 decomposeR mode (func:funcs) right
587 generateJsExpr mode $
588 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
591apply :: Opt.Expr -> Opt.Expr -> Opt.Expr
594 Opt.Accessor field ->
595 Opt.Access value field
598 Opt.Call f (args ++ [value])
601 Opt.Call func [value]
604append :: Mode -> Opt.Expr -> Opt.Expr -> JS.Expr
605append mode left right =
606 let seqs = generateJsExpr mode left : toSeqs mode right in
607 if any isStringLiteral seqs then
608 foldr1 (JS.Infix JS.OpAdd) seqs
613jsAppend :: JS.Expr -> JS.Expr -> JS.Expr
615 JS.Call (JS.Ref (Name.fromKernel N.utils "ap")) [a, b]
618toSeqs :: Mode -> Opt.Expr -> [JS.Expr]
621 Opt.Call (Opt.VarGlobal (Opt.Global home "append")) [left, right]
622 | home == ModuleName.basics ->
623 generateJsExpr mode left : toSeqs mode right
626 [generateJsExpr mode expr]
629isStringLiteral :: JS.Expr -> Bool
630isStringLiteral expr =
640-- SIMPLIFY INFIX OPERATORS
643strictEq :: JS.Expr -> JS.Expr -> JS.Expr
647 JS.Prefix JS.PrefixLNot right
650 if bool then right else JS.Prefix JS.PrefixLNot right
655 JS.Prefix JS.PrefixLNot left
658 if bool then left else JS.Prefix JS.PrefixLNot left
661 JS.Infix JS.OpStrictEq left right
664strictNEq :: JS.Expr -> JS.Expr -> JS.Expr
665strictNEq left right =
671 if bool then JS.Prefix JS.PrefixLNot right else right
679 if bool then JS.Prefix JS.PrefixLNot left else left
682 JS.Infix JS.OpStrictNEq left right
689-- TODO check if JS minifiers collapse unnecessary temporary variables
691generateTailCall :: Mode -> N.Name -> [(N.Name, Opt.Expr)] -> [JS.Stmt]
692generateTailCall mode name args =
694 toTempVars (argName, arg) =
695 ( Name.makeTemp argName, Just (generateJsExpr mode arg) )
697 toRealVars (argName, _) =
699 JS.Assign (JS.LRef (Name.fromLocal argName)) (JS.Ref (Name.makeTemp argName))
701 JS.Var (map toTempVars args)
702 : map toRealVars args
703 ++ [ JS.Continue (Just (Name.fromLocal name)) ]
710generateDef :: Mode -> Opt.Def -> JS.Stmt
711generateDef mode def =
714 JS.Var [ (Name.fromLocal name, Just (generateJsExpr mode body)) ]
716 Opt.TailDef name argNames body ->
719 JS.Function Nothing (map Name.fromLocal argNames)
720 [ JS.Labelled (Name.fromLocal name) $
721 JS.While (JS.Bool True) $
722 codeToStmt $ generate mode body
725 JS.Var [ (Name.fromLocal name, Just function) ]
732generatePath :: Mode -> Opt.Path -> JS.Expr
733generatePath mode path =
735 Opt.Index index subPath ->
736 JS.Access (generatePath mode subPath) (Name.fromIndex index)
739 JS.Ref (Name.fromLocal name)
741 Opt.Field field subPath ->
742 JS.Access (generatePath mode subPath) (Name.fromField mode field)
747 JS.Access (generatePath mode subPath) (Name.fromIndex Index.first)
750 generatePath mode subPath
757generateIf :: Mode -> [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> Code
758generateIf mode givenBranches givenFinal =
761 crushIfs givenBranches givenFinal
763 convertBranch (condition, expr) =
764 ( generateJsExpr mode condition
768 branchExprs = map convertBranch branches
769 finalCode = generate mode final
771 if isBlock finalCode || any (isBlock . snd) branchExprs then
772 JsBlock [ foldr addStmtIf (codeToStmt finalCode) branchExprs ]
774 JsExpr $ foldr addExprIf (codeToExpr finalCode) branchExprs
777addExprIf :: (JS.Expr, Code) -> JS.Expr -> JS.Expr
778addExprIf (condition, branch) final =
779 JS.If condition (codeToExpr branch) final
782addStmtIf :: (JS.Expr, Code) -> JS.Stmt -> JS.Stmt
783addStmtIf (condition, branch) final =
784 JS.IfStmt condition (codeToStmt branch) final
787isBlock :: Code -> Bool
794crushIfs :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
795crushIfs branches final =
796 crushIfsHelp [] branches final
800 :: [(Opt.Expr, Opt.Expr)]
801 -> [(Opt.Expr, Opt.Expr)]
803 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
804crushIfsHelp visitedBranches unvisitedBranches final =
805 case unvisitedBranches of
808 Opt.If subBranches subFinal ->
809 crushIfsHelp visitedBranches subBranches subFinal
812 (reverse visitedBranches, final)
814 visiting : unvisited ->
815 crushIfsHelp (visiting : visitedBranches) unvisited final
822generateCase :: Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> [JS.Stmt]
823generateCase mode label root decider jumps =
824 foldr (goto mode label) (generateDecider mode label root decider) jumps
827goto :: Mode -> N.Name -> (Int, Opt.Expr) -> [JS.Stmt] -> [JS.Stmt]
828goto mode label (index, branch) stmts =
832 (Name.makeLabel label index)
833 (JS.While (JS.Bool True) (JS.Block stmts))
835 labeledDeciderStmt : codeToStmtList (generate mode branch)
838generateDecider :: Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [JS.Stmt]
839generateDecider mode label root decisionTree =
841 Opt.Leaf (Opt.Inline branch) ->
842 codeToStmtList (generate mode branch)
844 Opt.Leaf (Opt.Jump index) ->
845 [ JS.Break (Just (Name.makeLabel label index)) ]
847 Opt.Chain testChain success failure ->
849 (List.foldl1' (JS.Infix JS.OpLAnd) (map (generateIfTest mode root) testChain))
850 (JS.Block $ generateDecider mode label root success)
851 (JS.Block $ generateDecider mode label root failure)
854 Opt.FanOut path edges fallback ->
856 (generateCaseTest mode root path (fst (head edges)))
858 (\edge cases -> generateCaseBranch mode label root edge : cases)
859 [ JS.Default (generateDecider mode label root fallback) ]
865generateIfTest :: Mode -> N.Name -> (DT.Path, DT.Test) -> JS.Expr
866generateIfTest mode root (path, test) =
868 value = pathToJsExpr mode root path
871 DT.IsCtor name index _ _ ->
872 strictEq (JS.Access value Name.dollar) $
874 Name.Debug _ -> JS.String (N.toBuilder name)
875 Name.Prod _ _ -> JS.Int (Index.toMachine index)
878 strictEq value (JS.Int int)
881 strictEq (JS.String (Text.encodeUtf8Builder char)) $
883 Name.Debug _ -> JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
884 Name.Prod _ _ -> value
887 strictEq value (JS.String (Text.encodeUtf8Builder string))
890 JS.Access value (Name.fromLocal "b")
893 JS.Prefix JS.PrefixLNot $
894 JS.Access value (Name.fromLocal "b")
897generateCaseBranch :: Mode -> N.Name -> N.Name -> (DT.Test, Opt.Decider Opt.Choice) -> JS.Case
898generateCaseBranch mode label root (test, subTree) =
900 (generateCaseValue mode test)
901 (generateDecider mode label root subTree)
904generateCaseValue :: Mode -> DT.Test -> JS.Expr
905generateCaseValue mode test =
907 DT.IsCtor name index _ _ ->
909 Name.Debug _ -> JS.String (N.toBuilder name)
910 Name.Prod _ _ -> JS.Int (Index.toMachine index)
916 JS.String (Text.encodeUtf8Builder char)
919 JS.String (Text.encodeUtf8Builder string)
922 error "COMPILER BUG - there should never be three tests on a list"
925 error "COMPILER BUG - there should never be three tests on a list"
928generateCaseTest :: Mode -> N.Name -> DT.Path -> DT.Test -> JS.Expr
929generateCaseTest mode root path exampleTest =
931 value = pathToJsExpr mode root path
934 DT.IsCtor _ _ _ opts ->
937 JS.Access value Name.dollar
942 JS.Access value Name.dollar
959 JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
965 error "COMPILER BUG - there should never be three tests on a list"
968 error "COMPILER BUG - there should never be three tests on a list"
975pathToJsExpr :: Mode -> N.Name -> DT.Path -> JS.Expr
976pathToJsExpr mode root path =
978 DT.Index index subPath ->
979 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex index)
984 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex Index.first)
987 pathToJsExpr mode root subPath
990 JS.Ref (Name.fromLocal root)
997generateMain :: Mode -> I.Interfaces -> ModuleName.Canonical -> Opt.Main -> JS.Expr
998generateMain mode interfaces home main =
1001 JS.Ref (Name.fromKernel N.browser "staticPage")
1002 # JS.Ref (Name.fromGlobal home "main")
1006 Opt.Dynamic decoder msgType ->
1007 JS.Ref (Name.fromGlobal home "main")
1008 # generateJsExpr mode decoder
1009 # toDebugMetadata mode interfaces msgType
1012(#) :: JS.Expr -> JS.Expr -> JS.Expr
1017toDebugMetadata :: Mode -> I.Interfaces -> Can.Type -> JS.Expr
1018toDebugMetadata mode interfaces msgType =
1024 JS.Json $ Encode.object $
1025 [ ("versions", Encode.object [ ("elm", Pkg.encodeVersion Version.version) ])
1026 , ("types", Type.encodeMetadata (Extract.fromMsg interfaces msgType))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list