1{-# LANGUAGE OverloadedStrings #-}
2module Generate.JavaScript.Expression
15import qualified Data.IntMap as IntMap
16import qualified Data.List as List
18import qualified Data.Map as Map
19import qualified Data.Text.Encoding as Text
21import qualified AST.Canonical as Can
22import qualified AST.Optimized as Opt
23import qualified AST.Module.Name as ModuleName
24import qualified Data.Index as Index
25import qualified Elm.Compiler.Type as Type
26import qualified Elm.Compiler.Type.Extract as Extract
27import qualified Elm.Name as N
28import qualified Elm.Package as Pkg
29import qualified Elm.Compiler.Version as Version
30import qualified Generate.JavaScript.Builder as JS
31import qualified Generate.JavaScript.Mode as Mode
32import qualified Generate.JavaScript.Name as Name
33import qualified Json.Encode as Encode
34import qualified Optimize.DecisionTree as DT
35import qualified Reporting.Region as R
42generateJsExpr :: Mode.Mode -> Opt.Expr -> JS.Expr
43generateJsExpr mode expression =
44 codeToExpr (generate mode expression)
47generate :: Mode.Mode -> Opt.Expr -> Code
48generate mode expression =
57 JS.Call toChar [ JS.String (Text.encodeUtf8Builder char) ]
60 JS.String (Text.encodeUtf8Builder char)
63 JsExpr $ JS.String (Text.encodeUtf8Builder string)
69 JsExpr $ JS.Float float
72 JsExpr $ JS.Ref (Name.fromLocal name)
74 Opt.VarGlobal (Opt.Global home name) ->
75 JsExpr $ JS.Ref (Name.fromGlobal home name)
77 Opt.VarEnum (Opt.Global home name) index ->
80 JsExpr $ JS.Ref (Name.fromGlobal home name)
83 JsExpr $ JS.Int (Index.toMachine index)
85 Opt.VarBox (Opt.Global home name) ->
88 Mode.Dev _ _ -> Name.fromGlobal home name
89 Mode.Prod _ _ -> Name.fromGlobal ModuleName.basics N.identity
91 Opt.VarCycle home name ->
92 JsExpr $ JS.Call (JS.Ref (Name.fromCycle home name)) []
94 Opt.VarDebug name home region unhandledValueName ->
95 JsExpr $ generateDebug name home region unhandledValueName
97 Opt.VarKernel home name ->
98 JsExpr $ JS.Ref (Name.fromKernel home name)
103 JsExpr $ JS.Ref (Name.fromKernel N.list "Nil")
108 (JS.Ref (Name.fromKernel N.list "fromArray"))
109 [ JS.Array $ map (generateJsExpr mode) entries
112 Opt.Function args body ->
113 generateFunction (map Name.fromLocal args) (generate mode body)
115 Opt.Call func args ->
116 JsExpr $ generateCall mode func args
118 Opt.TailCall name args ->
119 JsBlock $ generateTailCall mode name args
121 Opt.If branches final ->
122 generateIf mode branches final
126 generateDef mode def : codeToStmtList (generate mode body)
128 Opt.Destruct (Opt.Destructor name path) body ->
130 pathExpr = generatePath mode path
131 pathDef = JS.Var [ (Name.fromLocal name, Just pathExpr) ]
133 JsBlock $ pathDef : codeToStmtList (generate mode body)
135 Opt.Case label root decider jumps ->
136 JsBlock $ generateCase mode label root decider jumps
138 Opt.Accessor field ->
139 JsExpr $ JS.Function Nothing [Name.dollar]
141 JS.Access (JS.Ref Name.dollar) (generateField mode field)
144 Opt.Access record field ->
145 JsExpr $ JS.Access (generateJsExpr mode record) (generateField mode field)
147 Opt.Update record fields ->
149 JS.Call (JS.Ref (Name.fromKernel N.utils "update"))
150 [ generateJsExpr mode record
151 , generateRecord mode fields
155 JsExpr $ generateRecord mode fields
160 JsExpr $ JS.Ref (Name.fromKernel N.utils "Tuple0")
165 Opt.Tuple a b maybeC ->
169 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple2"))
170 [ generateJsExpr mode a
171 , generateJsExpr mode b
175 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple3"))
176 [ generateJsExpr mode a
177 , generateJsExpr mode b
178 , generateJsExpr mode c
182 let string = JS.String (Text.encodeUtf8Builder src) in
183 JsExpr $ JS.Object [ ( Name.fromLocal "src", string ) ]
195codeToExpr :: Code -> JS.Expr
201 JsBlock [ JS.Return (Just expr) ] ->
205 JS.Call (JS.Function Nothing [] stmts) []
208codeToStmtList :: Code -> [JS.Stmt]
211 JsExpr (JS.Call (JS.Function Nothing [] stmts) []) ->
215 [ JS.Return (Just expr) ]
221codeToStmt :: Code -> JS.Stmt
224 JsExpr (JS.Call (JS.Function Nothing [] stmts) []) ->
228 JS.Return (Just expr)
241{-# NOINLINE toChar #-}
244 JS.Ref (Name.fromKernel N.utils "chr")
251generateCtor :: Mode.Mode -> Opt.Global -> Index.ZeroBased -> Int -> Code
252generateCtor mode (Opt.Global home name) index arity =
255 Index.indexedMap (\i _ -> Name.fromIndex i) [1 .. arity]
259 Mode.Dev _ _ -> JS.String (N.toBuilder name)
260 Mode.Prod _ _ -> JS.Int (ctorToInt home name index)
262 generateFunction argNames $ JsExpr $ JS.Object $
263 (Name.dollar, ctorTag) : map (\n -> (n, JS.Ref n)) argNames
266ctorToInt :: ModuleName.Canonical -> N.Name -> Index.ZeroBased -> Int
267ctorToInt home name index =
268 if home == ModuleName.dict && name == "RBNode_elm_builtin" || name == "RBEmpty_elm_builtin" then
269 0 - Index.toHuman index
271 Index.toMachine index
278generateRecord :: Mode.Mode -> Map.Map N.Name Opt.Expr -> JS.Expr
279generateRecord mode fields =
281 toPair (field, value) =
282 (generateField mode field, generateJsExpr mode value)
284 JS.Object (map toPair (Map.toList fields))
287generateField :: Mode.Mode -> N.Name -> Name.Name
288generateField mode name =
293 Mode.Prod _ fields ->
302generateDebug :: N.Name -> ModuleName.Canonical -> R.Region -> Maybe N.Name -> JS.Expr
303generateDebug name (ModuleName.Canonical _ home) region unhandledValueName =
304 if name /= "todo" then
305 JS.Ref (Name.fromGlobal ModuleName.debug name)
307 case unhandledValueName of
309 JS.Call (JS.Ref (Name.fromKernel N.debug "todo")) $
310 [ JS.String (N.toBuilder home)
311 , regionToJsExpr region
315 JS.Call (JS.Ref (Name.fromKernel N.debug "todoCase")) $
316 [ JS.String (N.toBuilder home)
317 , regionToJsExpr region
318 , JS.Ref (Name.fromLocal valueName)
322regionToJsExpr :: R.Region -> JS.Expr
323regionToJsExpr (R.Region start end) =
325 [ ( Name.fromLocal "start", positionToJsExpr start )
326 , ( Name.fromLocal "end", positionToJsExpr end )
330positionToJsExpr :: R.Position -> JS.Expr
331positionToJsExpr (R.Position line column) =
333 [ ( Name.fromLocal "line", JS.Int line )
334 , ( Name.fromLocal "column", JS.Int column )
342generateFunction :: [Name.Name] -> Code -> Code
343generateFunction args body =
344 case IntMap.lookup (length args) funcHelpers of
348 [ JS.Function Nothing args $
355 JsExpr $ JS.Function Nothing [arg] $
358 foldr addArg body args
361{-# NOINLINE funcHelpers #-}
362funcHelpers :: IntMap.IntMap JS.Expr
365 map (\n -> (n, JS.Ref (Name.makeF n))) [2..9]
372generateCall :: Mode.Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
373generateCall mode func args =
375 Opt.VarGlobal global@(Opt.Global (ModuleName.Canonical pkg _) _) | pkg == Pkg.core ->
376 generateCoreCall mode global args
381 generateCallHelp mode func args
386 generateJsExpr mode arg
389 generateCallHelp mode func args
392 generateCallHelp mode func args
395generateCallHelp :: Mode.Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
396generateCallHelp mode func args =
398 (generateJsExpr mode func)
399 (map (generateJsExpr mode) args)
402generateGlobalCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
403generateGlobalCall home name args =
404 generateNormalCall (JS.Ref (Name.fromGlobal home name)) args
407generateNormalCall :: JS.Expr -> [JS.Expr] -> JS.Expr
408generateNormalCall func args =
409 case IntMap.lookup (length args) callHelpers of
411 JS.Call helper (func:args)
414 List.foldl' (\f a -> JS.Call f [a]) func args
417{-# NOINLINE callHelpers #-}
418callHelpers :: IntMap.IntMap JS.Expr
421 map (\n -> (n, JS.Ref (Name.makeA n))) [2..9]
428generateCoreCall :: Mode.Mode -> Opt.Global -> [Opt.Expr] -> JS.Expr
429generateCoreCall mode (Opt.Global home@(ModuleName.Canonical _ moduleName) name) args =
430 if moduleName == N.basics then
431 generateBasicsCall mode home name args
433 else if moduleName == N.bitwise then
434 generateBitwiseCall home name (map (generateJsExpr mode) args)
436 else if moduleName == N.tuple then
437 generateTupleCall home name (map (generateJsExpr mode) args)
439 else if moduleName == N.jsArray then
440 generateJsArrayCall home name (map (generateJsExpr mode) args)
443 generateGlobalCall home name (map (generateJsExpr mode) args)
446generateTupleCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
447generateTupleCall home name args =
451 "first" -> JS.Access value (Name.fromLocal "a")
452 "second" -> JS.Access value (Name.fromLocal "b")
453 _ -> generateGlobalCall home name args
456 generateGlobalCall home name args
459generateJsArrayCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
460generateJsArrayCall home name args =
462 [entry] | name == "singleton" -> JS.Array [entry]
463 [index, array] | name == "unsafeGet" -> JS.Index array index
464 _ -> generateGlobalCall home name args
467generateBitwiseCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
468generateBitwiseCall home name args =
472 "complement" -> JS.Prefix JS.PrefixBNot arg
473 _ -> generateGlobalCall home name args
477 "and" -> JS.Infix JS.OpBAnd left right
478 "or" -> JS.Infix JS.OpBOr left right
479 "xor" -> JS.Infix JS.OpBXor left right
480 "shiftLeftBy" -> JS.Infix JS.OpLShift right left
481 "shiftRightBy" -> JS.Infix JS.OpSpRShift right left
482 "shiftRightZfBy" -> JS.Infix JS.OpZfRShift right left
483 _ -> generateGlobalCall home name args
486 generateGlobalCall home name args
489generateBasicsCall :: Mode.Mode -> ModuleName.Canonical -> N.Name -> [Opt.Expr] -> JS.Expr
490generateBasicsCall mode home name args =
493 let arg = generateJsExpr mode elmArg in
495 "not" -> JS.Prefix JS.PrefixLNot arg
496 "negate" -> JS.Prefix JS.PrefixMinus arg
498 "truncate" -> JS.Infix JS.OpBOr arg (JS.Int 0)
499 _ -> generateGlobalCall home name [arg]
501 [elmLeft, elmRight] ->
503 -- NOTE: removed "composeL" and "composeR" because of this issue:
504 -- https://github.com/elm/compiler/issues/1722
505 "append" -> append mode elmLeft elmRight
506 "apL" -> generateJsExpr mode $ apply elmLeft elmRight
507 "apR" -> generateJsExpr mode $ apply elmRight elmLeft
510 left = generateJsExpr mode elmLeft
511 right = generateJsExpr mode elmRight
514 "add" -> JS.Infix JS.OpAdd left right
515 "sub" -> JS.Infix JS.OpSub left right
516 "mul" -> JS.Infix JS.OpMul left right
517 "fdiv" -> JS.Infix JS.OpDiv left right
518 "idiv" -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv left right) (JS.Int 0)
519 "eq" -> equal left right
520 "neq" -> notEqual left right
521 "lt" -> cmp JS.OpLT JS.OpLT 0 left right
522 "gt" -> cmp JS.OpGT JS.OpGT 0 left right
523 "le" -> cmp JS.OpLEq JS.OpLT 1 left right
524 "ge" -> cmp JS.OpGEq JS.OpGT (-1) left right
525 "or" -> JS.Infix JS.OpLOr left right
526 "and" -> JS.Infix JS.OpLAnd left right
527 "xor" -> JS.Infix JS.OpStrictNEq left right
528 "remainderBy" -> JS.Infix JS.OpMod right left
529 _ -> generateGlobalCall home name [left, right]
532 generateGlobalCall home name (map (generateJsExpr mode) args)
535equal :: JS.Expr -> JS.Expr -> JS.Expr
537 if isLiteral left || isLiteral right then
540 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
543notEqual :: JS.Expr -> JS.Expr -> JS.Expr
545 if isLiteral left || isLiteral right then
548 JS.Prefix JS.PrefixLNot $
549 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
552cmp :: JS.InfixOp -> JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
553cmp idealOp backupOp backupInt left right =
554 if isLiteral left || isLiteral right then
555 JS.Infix idealOp left right
558 (JS.Call (JS.Ref (Name.fromKernel N.utils "cmp")) [left, right])
562isLiteral :: JS.Expr -> Bool
581apply :: Opt.Expr -> Opt.Expr -> Opt.Expr
584 Opt.Accessor field ->
585 Opt.Access value field
588 Opt.Call f (args ++ [value])
591 Opt.Call func [value]
594append :: Mode.Mode -> Opt.Expr -> Opt.Expr -> JS.Expr
595append mode left right =
596 let seqs = generateJsExpr mode left : toSeqs mode right in
597 if any isStringLiteral seqs then
598 foldr1 (JS.Infix JS.OpAdd) seqs
603jsAppend :: JS.Expr -> JS.Expr -> JS.Expr
605 JS.Call (JS.Ref (Name.fromKernel N.utils "ap")) [a, b]
608toSeqs :: Mode.Mode -> Opt.Expr -> [JS.Expr]
611 Opt.Call (Opt.VarGlobal (Opt.Global home "append")) [left, right]
612 | home == ModuleName.basics ->
613 generateJsExpr mode left : toSeqs mode right
616 [generateJsExpr mode expr]
619isStringLiteral :: JS.Expr -> Bool
620isStringLiteral expr =
630-- SIMPLIFY INFIX OPERATORS
633strictEq :: JS.Expr -> JS.Expr -> JS.Expr
637 JS.Prefix JS.PrefixLNot right
640 if bool then right else JS.Prefix JS.PrefixLNot right
645 JS.Prefix JS.PrefixLNot left
648 if bool then left else JS.Prefix JS.PrefixLNot left
651 JS.Infix JS.OpStrictEq left right
654strictNEq :: JS.Expr -> JS.Expr -> JS.Expr
655strictNEq left right =
661 if bool then JS.Prefix JS.PrefixLNot right else right
669 if bool then JS.Prefix JS.PrefixLNot left else left
672 JS.Infix JS.OpStrictNEq left right
679-- TODO check if JS minifiers collapse unnecessary temporary variables
681generateTailCall :: Mode.Mode -> N.Name -> [(N.Name, Opt.Expr)] -> [JS.Stmt]
682generateTailCall mode name args =
684 toTempVars (argName, arg) =
685 ( Name.makeTemp argName, Just (generateJsExpr mode arg) )
687 toRealVars (argName, _) =
689 JS.Assign (JS.LRef (Name.fromLocal argName)) (JS.Ref (Name.makeTemp argName))
691 JS.Var (map toTempVars args)
692 : map toRealVars args
693 ++ [ JS.Continue (Just (Name.fromLocal name)) ]
700generateDef :: Mode.Mode -> Opt.Def -> JS.Stmt
701generateDef mode def =
704 JS.Var [ (Name.fromLocal name, Just (generateJsExpr mode body)) ]
706 Opt.TailDef name argNames body ->
707 JS.Var [ (Name.fromLocal name, Just (codeToExpr (generateTailDef mode name argNames body))) ]
710generateTailDef :: Mode.Mode -> N.Name -> [N.Name] -> Opt.Expr -> Code
711generateTailDef mode name argNames body =
712 generateFunction (map Name.fromLocal argNames) $ JsBlock $
713 [ JS.Labelled (Name.fromLocal name) $
714 JS.While (JS.Bool True) $
715 codeToStmt $ generate mode body
723generatePath :: Mode.Mode -> Opt.Path -> JS.Expr
724generatePath mode path =
726 Opt.Index index subPath ->
727 JS.Access (generatePath mode subPath) (Name.fromIndex index)
730 JS.Ref (Name.fromLocal name)
732 Opt.Field field subPath ->
733 JS.Access (generatePath mode subPath) (generateField mode field)
738 JS.Access (generatePath mode subPath) (Name.fromIndex Index.first)
741 generatePath mode subPath
748generateIf :: Mode.Mode -> [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> Code
749generateIf mode givenBranches givenFinal =
752 crushIfs givenBranches givenFinal
754 convertBranch (condition, expr) =
755 ( generateJsExpr mode condition
759 branchExprs = map convertBranch branches
760 finalCode = generate mode final
762 if isBlock finalCode || any (isBlock . snd) branchExprs then
763 JsBlock [ foldr addStmtIf (codeToStmt finalCode) branchExprs ]
765 JsExpr $ foldr addExprIf (codeToExpr finalCode) branchExprs
768addExprIf :: (JS.Expr, Code) -> JS.Expr -> JS.Expr
769addExprIf (condition, branch) final =
770 JS.If condition (codeToExpr branch) final
773addStmtIf :: (JS.Expr, Code) -> JS.Stmt -> JS.Stmt
774addStmtIf (condition, branch) final =
775 JS.IfStmt condition (codeToStmt branch) final
778isBlock :: Code -> Bool
785crushIfs :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
786crushIfs branches final =
787 crushIfsHelp [] branches final
791 :: [(Opt.Expr, Opt.Expr)]
792 -> [(Opt.Expr, Opt.Expr)]
794 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
795crushIfsHelp visitedBranches unvisitedBranches final =
796 case unvisitedBranches of
799 Opt.If subBranches subFinal ->
800 crushIfsHelp visitedBranches subBranches subFinal
803 (reverse visitedBranches, final)
805 visiting : unvisited ->
806 crushIfsHelp (visiting : visitedBranches) unvisited final
813generateCase :: Mode.Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> [JS.Stmt]
814generateCase mode label root decider jumps =
815 foldr (goto mode label) (generateDecider mode label root decider) jumps
818goto :: Mode.Mode -> N.Name -> (Int, Opt.Expr) -> [JS.Stmt] -> [JS.Stmt]
819goto mode label (index, branch) stmts =
823 (Name.makeLabel label index)
824 (JS.While (JS.Bool True) (JS.Block stmts))
826 labeledDeciderStmt : codeToStmtList (generate mode branch)
829generateDecider :: Mode.Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [JS.Stmt]
830generateDecider mode label root decisionTree =
832 Opt.Leaf (Opt.Inline branch) ->
833 codeToStmtList (generate mode branch)
835 Opt.Leaf (Opt.Jump index) ->
836 [ JS.Break (Just (Name.makeLabel label index)) ]
838 Opt.Chain testChain success failure ->
840 (List.foldl1' (JS.Infix JS.OpLAnd) (map (generateIfTest mode root) testChain))
841 (JS.Block $ generateDecider mode label root success)
842 (JS.Block $ generateDecider mode label root failure)
845 Opt.FanOut path edges fallback ->
847 (generateCaseTest mode root path (fst (head edges)))
849 (\edge cases -> generateCaseBranch mode label root edge : cases)
850 [ JS.Default (generateDecider mode label root fallback) ]
856generateIfTest :: Mode.Mode -> N.Name -> (DT.Path, DT.Test) -> JS.Expr
857generateIfTest mode root (path, test) =
859 value = pathToJsExpr mode root path
862 DT.IsCtor home name index _ opts ->
866 Mode.Dev _ _ -> JS.Access value Name.dollar
869 Can.Normal -> JS.Access value Name.dollar
875 Mode.Dev _ _ -> JS.String (N.toBuilder name)
876 Mode.Prod _ _ -> JS.Int (ctorToInt home name index)
882 JS.Prefix JS.PrefixLNot value
885 strictEq value (JS.Int int)
888 strictEq (JS.String (Text.encodeUtf8Builder char)) $
890 Mode.Dev _ _ -> JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
891 Mode.Prod _ _ -> value
894 strictEq value (JS.String (Text.encodeUtf8Builder string))
897 JS.Access value (Name.fromLocal "b")
900 JS.Prefix JS.PrefixLNot $
901 JS.Access value (Name.fromLocal "b")
904 error "COMPILER BUG - there should never be tests on a tuple"
908generateCaseBranch :: Mode.Mode -> N.Name -> N.Name -> (DT.Test, Opt.Decider Opt.Choice) -> JS.Case
909generateCaseBranch mode label root (test, subTree) =
911 (generateCaseValue mode test)
912 (generateDecider mode label root subTree)
915generateCaseValue :: Mode.Mode -> DT.Test -> JS.Expr
916generateCaseValue mode test =
918 DT.IsCtor home name index _ _ ->
920 Mode.Dev _ _ -> JS.String (N.toBuilder name)
921 Mode.Prod _ _ -> JS.Int (ctorToInt home name index)
927 JS.String (Text.encodeUtf8Builder char)
930 JS.String (Text.encodeUtf8Builder string)
933 error "COMPILER BUG - there should never be three tests on a boolean"
936 error "COMPILER BUG - there should never be three tests on a list"
939 error "COMPILER BUG - there should never be three tests on a list"
942 error "COMPILER BUG - there should never be three tests on a tuple"
945generateCaseTest :: Mode.Mode -> N.Name -> DT.Path -> DT.Test -> JS.Expr
946generateCaseTest mode root path exampleTest =
948 value = pathToJsExpr mode root path
951 DT.IsCtor home name _ _ opts ->
952 if name == N.bool && home == ModuleName.basics then
957 JS.Access value Name.dollar
962 JS.Access value Name.dollar
979 JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
985 error "COMPILER BUG - there should never be three tests on a list"
988 error "COMPILER BUG - there should never be three tests on a list"
991 error "COMPILER BUG - there should never be three tests on a list"
994 error "COMPILER BUG - there should never be three tests on a list"
1001pathToJsExpr :: Mode.Mode -> N.Name -> DT.Path -> JS.Expr
1002pathToJsExpr mode root path =
1004 DT.Index index subPath ->
1005 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex index)
1010 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex Index.first)
1013 pathToJsExpr mode root subPath
1016 JS.Ref (Name.fromLocal root)
1023generateMain :: Mode.Mode -> ModuleName.Canonical -> Opt.Main -> JS.Expr
1024generateMain mode home main =
1027 JS.Ref (Name.fromKernel N.virtualDom "init")
1028 # JS.Ref (Name.fromGlobal home "main")
1032 Opt.Dynamic msgType decoder ->
1033 JS.Ref (Name.fromGlobal home "main")
1034 # generateJsExpr mode decoder
1035 # toDebugMetadata mode msgType
1038(#) :: JS.Expr -> JS.Expr -> JS.Expr
1043toDebugMetadata :: Mode.Mode -> Can.Type -> JS.Expr
1044toDebugMetadata mode msgType =
1049 Mode.Dev _ Nothing ->
1052 Mode.Dev _ (Just interfaces) ->
1053 JS.Json $ Encode.object $
1054 [ ("versions", Encode.object [ ("elm", Pkg.encodeVersion Version.version) ])
1055 , ("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