holy boy, no more typing things

This commit is contained in:
Ryan Haskell-Glatz 2019-10-30 23:55:56 -05:00
parent cd32e1cc00
commit 7e1fd98caf
12 changed files with 213 additions and 146 deletions

View File

@ -11,7 +11,7 @@ const main = ([ command, ...args ] = []) => {
generate: generate generate: generate
} }
return (commands[command] || commands['help'])(args || []) return (commands[command] || commands.help)(args || [])
} }
const generate = ([ relative = '.' ] = []) => const generate = ([ relative = '.' ] = []) =>
@ -38,7 +38,7 @@ const dir = (filepath) => {
.then(utils.all(tag)) .then(utils.all(tag))
} }
const passToElm = (json) => new Promise((resolve, reject) => { const passToElm = (json) => new Promise((resolve) => {
const app = Elm.Main.init({ flags: json }) const app = Elm.Main.init({ flags: json })
app.ports.toJs.subscribe(stuff => resolve(stuff)) app.ports.toJs.subscribe(stuff => resolve(stuff))
}) })

View File

@ -2,8 +2,8 @@ port module Main exposing (main)
import Item exposing (Item) import Item exposing (Item)
import Json.Decode as D exposing (Decoder) import Json.Decode as D exposing (Decoder)
import Templates.TopLevelPages import Templates.Pages
import Templates.TopLevelRoute import Templates.Route
port toJs : List NewFile -> Cmd msg port toJs : List NewFile -> Cmd msg
@ -40,38 +40,72 @@ parse =
decoder : Decoder (List NewFile) decoder : Decoder (List NewFile)
decoder = decoder =
D.list Item.decoder D.list Item.decoder
|> D.map (toFileInfo [])
|> D.map fromData |> D.map fromData
fromData : List Item -> List NewFile type alias FileInfo =
fromData items = { path : List String
, items : List Item
}
toFileInfo : List String -> List Item -> List FileInfo
toFileInfo path items =
List.foldl
(\folder infos ->
infos ++ toFileInfo (path ++ [ folder.name ]) folder.children
)
[ { path = path, items = items }
]
(Item.folders items)
fromData : List FileInfo -> List NewFile
fromData fileInfos =
List.concat List.concat
[ [ topLevelRoute items ] [ List.map routeFile fileInfos
, [ topLevelPages items ] , List.map pageFile fileInfos
, nestedRoutes items
, nestedPages items
] ]
topLevelPages : List Item -> NewFile routeFile : FileInfo -> NewFile
topLevelPages items = routeFile { path, items } =
{ filepathSegments = [ "Generated", "Pages.elm" ] { filepathSegments = segments "Pages" path
, contents = Templates.TopLevelPages.contents items , contents = Templates.Pages.contents items path
} }
topLevelRoute : List Item -> NewFile pageFile : FileInfo -> NewFile
topLevelRoute items = pageFile { path, items } =
{ filepathSegments = [ "Generated", "Route.elm" ] { filepathSegments = segments "Route" path
, contents = Templates.TopLevelRoute.contents items , contents = Templates.Route.contents items path
} }
nestedRoutes : List Item -> List NewFile segments : String -> List String -> List String
nestedRoutes _ = segments prefix path =
[] "Generated"
:: (if List.isEmpty path then
[ prefix ++ ".elm" ]
else
prefix :: appendToLast ".elm" path
)
nestedPages : List Item -> List NewFile appendToLast : String -> List String -> List String
nestedPages _ = appendToLast str list =
[] let
lastIndex =
List.length list - 1
in
List.indexedMap
(\i value ->
if i == lastIndex then
value ++ str
else
value
)
list

View File

@ -1,39 +1,35 @@
module Templates.TopLevelPages exposing (contents) module Templates.Pages exposing (contents)
import Item exposing (Item) import Item exposing (Item)
import Templates.Shared as Shared import Templates.Shared as Shared
contents : List Item -> String contents : List Item -> List String -> String
contents items = contents items path =
"""module Generated.Pages exposing """module {{module_}} exposing
( Model ( Model
, Msg , Msg
, page , page
) )
import Application.Page as Page exposing (Page) import Application.Page as Page
{{folderImports}} {{folderImports}}
import Generated.Route as Route exposing (Route) import {{routeModule}} as Route
import Global import {{ui}}
import Layouts.Main as Layout import {{layoutModule}} as Layout
{{fileImports}} {{fileImports}}
-- MODEL & MSG
{{models}} {{models}}
{{msgs}} {{msgs}}
page : Page Route Model Msg a b Global.Model Global.Msg c
page = page =
Page.layout Page.layout
{ view = Layout.view { map = {{ui}}.map
, view = Layout.view
, pages = , pages =
{ init = init { init = init
, update = update , update = update
@ -42,49 +38,30 @@ page =
} }
-- RECIPES
{{recipes}} {{recipes}}
-- INIT
{{init}} {{init}}
-- UPDATE
{{update}} {{update}}
{{updateLastCase}}
_ ->
Page.keep model_
-- BUNDLE
{{bundle}} {{bundle}}
""" """
|> String.replace "{{fileImports}}" (fileImports items) |> String.replace "{{module_}}" (module_ path)
|> String.replace "{{folderImports}}" (folderImports items) |> String.replace "{{routeModule}}" (routeModule path)
|> String.replace "{{layoutModule}}" (layoutModule path)
|> String.replace "{{fileImports}}" (fileImports items path)
|> String.replace "{{folderImports}}" (folderImports items path)
|> String.replace "{{models}}" (Shared.customTypes "Model" items) |> String.replace "{{models}}" (Shared.customTypes "Model" items)
|> String.replace "{{msgs}}" (Shared.customTypes "Msg" items) |> String.replace "{{msgs}}" (Shared.customTypes "Msg" items)
|> String.replace "{{recipes}}" (recipes items) |> String.replace "{{recipes}}" (recipes items)
|> String.replace "{{init}}" |> String.replace "{{init}}"
(topLevelFunction (topLevelFunction
{ name = "init" { name = "init"
, types =
{ input = "Route"
, output = "Page.Init Model Msg Global.Model Global.Msg"
}
, inputs = "route_" , inputs = "route_"
, caseExpression = , caseExpression =
{ value = "route_" { value = "route_"
@ -97,10 +74,6 @@ page =
|> String.replace "{{update}}" |> String.replace "{{update}}"
(topLevelFunction (topLevelFunction
{ name = "update" { name = "update"
, types =
{ input = "Msg -> Model"
, output = "Page.Update Model Msg Global.Model Global.Msg"
}
, inputs = "msg_ model_" , inputs = "msg_ model_"
, caseExpression = , caseExpression =
{ value = "( msg_, model_ )" { value = "( msg_, model_ )"
@ -110,13 +83,10 @@ page =
} }
items items
) )
|> String.replace "{{updateLastCase}}" (updateLastCase items)
|> String.replace "{{bundle}}" |> String.replace "{{bundle}}"
(topLevelFunction (topLevelFunction
{ name = "bundle" { name = "bundle"
, types =
{ input = "Model"
, output = "Page.Bundle Msg Global.Model Global.Msg a"
}
, inputs = "model_" , inputs = "model_"
, caseExpression = , caseExpression =
{ value = "model_" { value = "model_"
@ -126,6 +96,28 @@ page =
} }
items items
) )
|> String.replace "{{ui}}" "Html"
module_ : List String -> String
module_ path =
"Generated.Pages" ++ (path |> List.map ((++) ".") |> String.concat)
routeModule : List String -> String
routeModule path =
"Generated.Route" ++ (path |> List.map ((++) ".") |> String.concat)
layoutModule : List String -> String
layoutModule path =
"Layouts"
++ (if path == [] then
".Main"
else
path |> List.map ((++) ".") |> String.concat
)
{-| fileImports {-| fileImports
@ -137,10 +129,20 @@ page =
import Pages.SignIn as SignIn import Pages.SignIn as SignIn
-} -}
fileImports : List Item -> String fileImports : List Item -> List String -> String
fileImports items = fileImports items path =
Item.files items Item.files items
|> List.map (\file -> String.concat [ "import Pages.", file.name, " as ", file.name ]) |> List.map
(\file ->
String.concat
[ "import Pages"
, path |> List.map ((++) ".") |> String.concat
, "."
, file.name
, " as "
, file.name
]
)
|> String.join "\n" |> String.join "\n"
@ -150,10 +152,20 @@ fileImports items =
import Generated.Pages.Users as Users import Generated.Pages.Users as Users
-} -}
folderImports : List Item -> String folderImports : List Item -> List String -> String
folderImports items = folderImports items path =
Item.folders items Item.folders items
|> List.map (\folder -> String.concat [ "import Generated.Pages.", folder.name, " as ", folder.name ]) |> List.map
(\folder ->
String.concat
[ "import Generated.Pages"
, path |> List.map ((++) ".") |> String.concat
, "."
, folder.name
, " as "
, folder.name
]
)
|> String.join "\n" |> String.join "\n"
@ -177,11 +189,11 @@ recipes items =
-} -}
recipe : String -> String recipe : String -> String
recipe name = recipe name =
"""{{camelCase}} : Page.Recipe Route.{{name}}Params {{name}}.Model {{name}}.Msg Model Msg Global.Model Global.Msg msg """{{camelCase}} =
{{camelCase}} =
{{name}}.page {{name}}.page
{ toModel = {{name}}Model { toModel = {{name}}Model
, toMsg = {{name}}Msg , toMsg = {{name}}Msg
, map = {{ui}}.map
}""" }"""
|> String.replace "{{camelCase}}" (camelCase name) |> String.replace "{{camelCase}}" (camelCase name)
|> String.replace "{{name}}" name |> String.replace "{{name}}" name
@ -204,10 +216,6 @@ camelCase name =
type alias TopLevelFunctionOptions = type alias TopLevelFunctionOptions =
{ name : String { name : String
, types :
{ input : String
, output : String
}
, inputs : String , inputs : String
, caseExpression : CaseExpression , caseExpression : CaseExpression
} }
@ -224,10 +232,6 @@ type alias CaseExpression =
topLevelFunction topLevelFunction
{ name = "update" { name = "update"
, types =
{ input = "Msg -> Model"
, output = "Page.Update Model Msg Global.Model Global.Msg"
}
, inputs = "msg_ model_" , inputs = "msg_ model_"
, caseExpression = , caseExpression =
{ value = "( msg_, model_ )" { value = "( msg_, model_ )"
@ -237,7 +241,6 @@ type alias CaseExpression =
} }
[ "Counter", "Index", "NotFound" ] [ "Counter", "Index", "NotFound" ]
update : Msg -> Model -> Page.Update Model Msg Global.Model Global.Msg
update msg_ model_ = update msg_ model_ =
case ( msg_, model_ ) of case ( msg_, model_ ) of
( CounterMsg msg, CounterModel model ) -> ( CounterMsg msg, CounterModel model ) ->
@ -252,13 +255,10 @@ type alias CaseExpression =
-} -}
topLevelFunction : TopLevelFunctionOptions -> List Item -> String topLevelFunction : TopLevelFunctionOptions -> List Item -> String
topLevelFunction options items = topLevelFunction options items =
"""{{name}} : {{types.input}} -> {{types.output}} """{{name}} {{inputs}} =
{{name}} {{inputs}} =
case {{caseExpression.value}} of case {{caseExpression.value}} of
{{conditions}}""" {{conditions}}"""
|> String.replace "{{name}}" options.name |> String.replace "{{name}}" options.name
|> String.replace "{{types.input}}" options.types.input
|> String.replace "{{types.output}}" options.types.output
|> String.replace "{{inputs}}" options.inputs |> String.replace "{{inputs}}" options.inputs
|> String.replace "{{caseExpression.value}}" options.caseExpression.value |> String.replace "{{caseExpression.value}}" options.caseExpression.value
|> String.replace "{{conditions}}" (conditions options.caseExpression items) |> String.replace "{{conditions}}" (conditions options.caseExpression items)
@ -276,3 +276,14 @@ conditions caseExpression items =
|> String.replace "{{result}}" (caseExpression.result name) |> String.replace "{{result}}" (caseExpression.result name)
) )
|> String.join "\n\n " |> String.join "\n\n "
updateLastCase : List a -> String
updateLastCase list =
if List.length list > 1 then
"""
_ ->
Page.keep model_"""
else
""

View File

@ -1,25 +1,18 @@
module Templates.TopLevelRoute exposing (contents) module Templates.Route exposing (contents)
import Item exposing (Item) import Item exposing (Item)
import Templates.Shared as Shared import Templates.Shared as Shared
contents : List Item -> String contents : List Item -> List String -> String
contents items = contents items path =
"""module Generated.Route exposing """module {{module_}} exposing
( Route(..) ( Route(..)
, routes , routes
, toPath , toPath
, {{exports}} , {{exports}}
) )
{-|
@docs Route
@docs routes
@docs toPath
-}
import Application.Route as Route import Application.Route as Route
{{folderImports}} {{folderImports}}
@ -34,20 +27,19 @@ import Application.Route as Route
{{routeTypes}} {{routeTypes}}
routes : List (Route.Route Route)
routes = routes =
[ {{routes}} [ {{routes}}
] ]
toPath : Route -> String
toPath route = toPath route =
case route of case route of
{{toPath}} {{toPath}}
""" """
|> String.replace "{{module_}}" (module_ path)
|> String.replace "{{exports}}" (exports items) |> String.replace "{{exports}}" (exports items)
|> String.replace "{{folderImports}}" (folderImports items) |> String.replace "{{folderImports}}" (folderImports items path)
|> String.replace "{{fileParams}}" (fileParams items) |> String.replace "{{fileParams}}" (fileParams items)
|> String.replace "{{folderParams}}" (folderParams items) |> String.replace "{{folderParams}}" (folderParams items)
|> String.replace "{{routeTypes}}" |> String.replace "{{routeTypes}}"
@ -62,6 +54,11 @@ toPath route =
|> String.replace "{{toPath}}" (toPath items) |> String.replace "{{toPath}}" (toPath items)
module_ : List String -> String
module_ path =
"Generated.Route" ++ (path |> List.map ((++) ".") |> String.concat)
exports : List Item -> String exports : List Item -> String
exports items = exports items =
items items
@ -70,10 +67,20 @@ exports items =
|> String.join "\n , " |> String.join "\n , "
folderImports : List Item -> String folderImports : List Item -> List String -> String
folderImports items = folderImports items path =
Item.folders items Item.folders items
|> List.map (\{ name } -> String.concat [ "import Generated.Route.", name, " as ", name ]) |> List.map
(\{ name } ->
String.concat
[ "import Generated.Route"
, path |> List.map ((++) ".") |> String.concat
, "."
, name
, " as "
, name
]
)
|> String.join "\n" |> String.join "\n"
@ -121,17 +128,20 @@ routes items =
if name == "Index" then if name == "Index" then
"Route.index Index" "Route.index Index"
else if name == "Slug" then
"Route.slug Slug"
else else
String.concat [ "Route.path \"", path name, "\" ", name ] String.concat [ "Route.path \"", pathOf name, "\" ", name ]
) )
, Item.folders items , Item.folders items
|> List.map (\{ name } -> String.concat [ "Route.folder \"", path name, "\" ", name, " ", name, ".routes" ]) |> List.map (\{ name } -> String.concat [ "Route.folder \"", pathOf name, "\" ", name, " ", name, ".routes" ])
] ]
|> String.join "\n , " |> String.join "\n , "
path : String -> String pathOf : String -> String
path name = pathOf name =
name name
|> String.toList |> String.toList
|> List.map |> List.map
@ -158,7 +168,7 @@ toPath items =
String.concat String.concat
[ name [ name
, " _ ->\n \"/" , " _ ->\n \"/"
, path name , pathOf name
, "\"" , "\""
] ]
) )
@ -168,7 +178,7 @@ toPath items =
String.concat String.concat
[ name [ name
, " route_ ->\n \"/" , " route_ ->\n \"/"
, path name , pathOf name
, "\" ++ " , "\" ++ "
, name , name
, ".toPath route_" , ".toPath route_"

View File

@ -40,7 +40,7 @@ type Msg
page = page =
Page.layout Page.layout
{ map = Html.map { map = Html.map
, layout = Layout.view , view = Layout.view
, pages = , pages =
{ init = init { init = init
, update = update , update = update
@ -178,3 +178,4 @@ bundle model_ =
UsersModel model -> UsersModel model ->
users.bundle model users.bundle model

View File

@ -4,7 +4,8 @@ module Generated.Pages.Settings exposing
, page , page
) )
import Application.Page as Application import Application.Page as Page
import Generated.Route.Settings as Route import Generated.Route.Settings as Route
import Html import Html
import Layouts.Settings as Layout import Layouts.Settings as Layout
@ -26,9 +27,9 @@ type Msg
page = page =
Application.layout Page.layout
{ map = Html.map { map = Html.map
, layout = Layout.view , view = Layout.view
, pages = , pages =
{ init = init { init = init
, update = update , update = update
@ -85,7 +86,7 @@ update msg_ model_ =
user.update msg model user.update msg model
_ -> _ ->
Application.keep model_ Page.keep model_
bundle model_ = bundle model_ =
@ -98,3 +99,4 @@ bundle model_ =
UserModel model -> UserModel model ->
user.bundle model user.bundle model

View File

@ -4,7 +4,8 @@ module Generated.Pages.Users exposing
, page , page
) )
import Application.Page as Application import Application.Page as Page
import Generated.Route.Users as Route import Generated.Route.Users as Route
import Html import Html
import Layouts.Users as Layout import Layouts.Users as Layout
@ -20,9 +21,9 @@ type Msg
page = page =
Application.layout Page.layout
{ map = Html.map { map = Html.map
, layout = Layout.view , view = Layout.view
, pages = , pages =
{ init = init { init = init
, update = update , update = update
@ -51,7 +52,9 @@ update msg_ model_ =
slug.update msg model slug.update msg model
bundle model_ = bundle model_ =
case model_ of case model_ of
SlugModel model -> SlugModel model ->
slug.bundle model slug.bundle model

View File

@ -1,17 +1,17 @@
module Generated.Route exposing module Generated.Route exposing
( CounterParams ( Route(..)
, routes
, toPath
, CounterParams
, IndexParams , IndexParams
, NotFoundParams , NotFoundParams
, RandomParams , RandomParams
, Route(..)
, SettingsParams , SettingsParams
, SignInParams , SignInParams
, UsersParams , UsersParams
, routes
, shouldTransition
, toPath
) )
import Application.Route as Route import Application.Route as Route
import Generated.Route.Settings as Settings import Generated.Route.Settings as Settings
import Generated.Route.Users as Users import Generated.Route.Users as Users
@ -55,7 +55,6 @@ type Route
| Users UsersParams | Users UsersParams
routes : List (Route.Route Route)
routes = routes =
[ Route.path "counter" Counter [ Route.path "counter" Counter
, Route.index Index , Route.index Index
@ -67,7 +66,6 @@ routes =
] ]
toPath : Route -> String
toPath route = toPath route =
case route of case route of
Counter _ -> Counter _ ->
@ -91,7 +89,3 @@ toPath route =
Users route_ -> Users route_ ->
"/users" ++ Users.toPath route_ "/users" ++ Users.toPath route_
shouldTransition : List String -> List String -> Bool
shouldTransition _ _ =
True

View File

@ -1,15 +1,17 @@
module Generated.Route.Settings exposing module Generated.Route.Settings exposing
( AccountParams ( Route(..)
, NotificationsParams
, Route(..)
, UserParams
, routes , routes
, toPath , toPath
, AccountParams
, NotificationsParams
, UserParams
) )
import Application.Route as Route import Application.Route as Route
type alias AccountParams = type alias AccountParams =
() ()
@ -22,6 +24,9 @@ type alias UserParams =
() ()
type Route type Route
= Account AccountParams = Account AccountParams
| Notifications NotificationsParams | Notifications NotificationsParams
@ -45,3 +50,4 @@ toPath route =
User _ -> User _ ->
"/user" "/user"

View File

@ -1,17 +1,22 @@
module Generated.Route.Users exposing module Generated.Route.Users exposing
( Route(..) ( Route(..)
, SlugParams
, routes , routes
, toPath , toPath
, SlugParams
) )
import Application.Route as Route import Application.Route as Route
type alias SlugParams = type alias SlugParams =
String String
type Route type Route
= Slug SlugParams = Slug SlugParams
@ -23,5 +28,6 @@ routes =
toPath route = toPath route =
case route of case route of
Slug slug -> Slug _ ->
"/" ++ slug "/slug"

View File

@ -8,7 +8,7 @@
"build": "npm run build:example", "build": "npm run build:example",
"build:generator": "(cd cli && elm make src/Main.elm --optimize --output dist/elm.compiled.js > /dev/null)", "build:generator": "(cd cli && elm make src/Main.elm --optimize --output dist/elm.compiled.js > /dev/null)",
"build:example": "parcel build examples/html/index.html", "build:example": "parcel build examples/html/index.html",
"generate": "npm run build:generator && node ./cli/index.js run example" "generate": "npm run build:generator && node ./cli/index.js run examples/html"
}, },
"bin": "./cli/index.js", "bin": "./cli/index.js",
"keywords": [], "keywords": [],

View File

@ -172,7 +172,7 @@ element page { toModel, toMsg, map } =
type alias Layout pageRoute pageModel pageMsg globalModel globalMsg msg htmlPageMsg htmlMsg = type alias Layout pageRoute pageModel pageMsg globalModel globalMsg msg htmlPageMsg htmlMsg =
{ map : (pageMsg -> msg) -> htmlPageMsg -> htmlMsg { map : (pageMsg -> msg) -> htmlPageMsg -> htmlMsg
, layout : , view :
{ page : htmlMsg { page : htmlMsg
, global : globalModel , global : globalModel
} }
@ -184,7 +184,7 @@ type alias Layout pageRoute pageModel pageMsg globalModel globalMsg msg htmlPage
layout : layout :
Layout pageRoute pageModel pageMsg globalModel globalMsg msg htmlPageMsg htmlMsg Layout pageRoute pageModel pageMsg globalModel globalMsg msg htmlPageMsg htmlMsg
-> Page pageRoute pageModel pageMsg htmlPageMsg layoutModel layoutMsg htmlLayoutMsg globalModel globalMsg msg htmlMsg -> Page pageRoute pageModel pageMsg htmlPageMsg layoutModel layoutMsg htmlLayoutMsg globalModel globalMsg msg htmlMsg
layout options { toModel, toMsg, map } = layout options { toModel, toMsg } =
let let
pages = pages =
options.pages options.pages
@ -212,7 +212,7 @@ layout options { toModel, toMsg, map } =
in in
{ title = bundle.title { title = bundle.title
, view = , view =
options.layout options.view
{ page = bundle.view { page = bundle.view
, global = context.global , global = context.global
} }