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

View File

@ -2,8 +2,8 @@ port module Main exposing (main)
import Item exposing (Item)
import Json.Decode as D exposing (Decoder)
import Templates.TopLevelPages
import Templates.TopLevelRoute
import Templates.Pages
import Templates.Route
port toJs : List NewFile -> Cmd msg
@ -40,38 +40,72 @@ parse =
decoder : Decoder (List NewFile)
decoder =
D.list Item.decoder
|> D.map (toFileInfo [])
|> D.map fromData
fromData : List Item -> List NewFile
fromData items =
type alias FileInfo =
{ 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
[ [ topLevelRoute items ]
, [ topLevelPages items ]
, nestedRoutes items
, nestedPages items
[ List.map routeFile fileInfos
, List.map pageFile fileInfos
]
topLevelPages : List Item -> NewFile
topLevelPages items =
{ filepathSegments = [ "Generated", "Pages.elm" ]
, contents = Templates.TopLevelPages.contents items
routeFile : FileInfo -> NewFile
routeFile { path, items } =
{ filepathSegments = segments "Pages" path
, contents = Templates.Pages.contents items path
}
topLevelRoute : List Item -> NewFile
topLevelRoute items =
{ filepathSegments = [ "Generated", "Route.elm" ]
, contents = Templates.TopLevelRoute.contents items
pageFile : FileInfo -> NewFile
pageFile { path, items } =
{ filepathSegments = segments "Route" path
, contents = Templates.Route.contents items path
}
nestedRoutes : List Item -> List NewFile
nestedRoutes _ =
[]
segments : String -> List String -> List String
segments prefix path =
"Generated"
:: (if List.isEmpty path then
[ prefix ++ ".elm" ]
else
prefix :: appendToLast ".elm" path
)
nestedPages : List Item -> List NewFile
nestedPages _ =
[]
appendToLast : String -> List String -> List String
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 Templates.Shared as Shared
contents : List Item -> String
contents items =
"""module Generated.Pages exposing
contents : List Item -> List String -> String
contents items path =
"""module {{module_}} exposing
( Model
, Msg
, page
)
import Application.Page as Page exposing (Page)
import Application.Page as Page
{{folderImports}}
import Generated.Route as Route exposing (Route)
import Global
import Layouts.Main as Layout
import {{routeModule}} as Route
import {{ui}}
import {{layoutModule}} as Layout
{{fileImports}}
-- MODEL & MSG
{{models}}
{{msgs}}
page : Page Route Model Msg a b Global.Model Global.Msg c
page =
Page.layout
{ view = Layout.view
{ map = {{ui}}.map
, view = Layout.view
, pages =
{ init = init
, update = update
@ -42,49 +38,30 @@ page =
}
-- RECIPES
{{recipes}}
-- INIT
{{init}}
-- UPDATE
{{update}}
_ ->
Page.keep model_
-- BUNDLE
{{updateLastCase}}
{{bundle}}
"""
|> String.replace "{{fileImports}}" (fileImports items)
|> String.replace "{{folderImports}}" (folderImports items)
|> String.replace "{{module_}}" (module_ path)
|> 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 "{{msgs}}" (Shared.customTypes "Msg" items)
|> String.replace "{{recipes}}" (recipes items)
|> String.replace "{{init}}"
(topLevelFunction
{ name = "init"
, types =
{ input = "Route"
, output = "Page.Init Model Msg Global.Model Global.Msg"
}
, inputs = "route_"
, caseExpression =
{ value = "route_"
@ -97,10 +74,6 @@ page =
|> String.replace "{{update}}"
(topLevelFunction
{ name = "update"
, types =
{ input = "Msg -> Model"
, output = "Page.Update Model Msg Global.Model Global.Msg"
}
, inputs = "msg_ model_"
, caseExpression =
{ value = "( msg_, model_ )"
@ -110,13 +83,10 @@ page =
}
items
)
|> String.replace "{{updateLastCase}}" (updateLastCase items)
|> String.replace "{{bundle}}"
(topLevelFunction
{ name = "bundle"
, types =
{ input = "Model"
, output = "Page.Bundle Msg Global.Model Global.Msg a"
}
, inputs = "model_"
, caseExpression =
{ value = "model_"
@ -126,6 +96,28 @@ page =
}
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
@ -137,10 +129,20 @@ page =
import Pages.SignIn as SignIn
-}
fileImports : List Item -> String
fileImports items =
fileImports : List Item -> List String -> String
fileImports items path =
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"
@ -150,10 +152,20 @@ fileImports items =
import Generated.Pages.Users as Users
-}
folderImports : List Item -> String
folderImports items =
folderImports : List Item -> List String -> String
folderImports items path =
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"
@ -177,11 +189,11 @@ recipes items =
-}
recipe : String -> String
recipe name =
"""{{camelCase}} : Page.Recipe Route.{{name}}Params {{name}}.Model {{name}}.Msg Model Msg Global.Model Global.Msg msg
{{camelCase}} =
"""{{camelCase}} =
{{name}}.page
{ toModel = {{name}}Model
, toMsg = {{name}}Msg
, map = {{ui}}.map
}"""
|> String.replace "{{camelCase}}" (camelCase name)
|> String.replace "{{name}}" name
@ -204,10 +216,6 @@ camelCase name =
type alias TopLevelFunctionOptions =
{ name : String
, types :
{ input : String
, output : String
}
, inputs : String
, caseExpression : CaseExpression
}
@ -224,10 +232,6 @@ type alias CaseExpression =
topLevelFunction
{ name = "update"
, types =
{ input = "Msg -> Model"
, output = "Page.Update Model Msg Global.Model Global.Msg"
}
, inputs = "msg_ model_"
, caseExpression =
{ value = "( msg_, model_ )"
@ -237,7 +241,6 @@ type alias CaseExpression =
}
[ "Counter", "Index", "NotFound" ]
update : Msg -> Model -> Page.Update Model Msg Global.Model Global.Msg
update msg_ model_ =
case ( msg_, model_ ) of
( CounterMsg msg, CounterModel model ) ->
@ -252,13 +255,10 @@ type alias CaseExpression =
-}
topLevelFunction : TopLevelFunctionOptions -> List Item -> String
topLevelFunction options items =
"""{{name}} : {{types.input}} -> {{types.output}}
{{name}} {{inputs}} =
"""{{name}} {{inputs}} =
case {{caseExpression.value}} of
{{conditions}}"""
|> 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 "{{caseExpression.value}}" options.caseExpression.value
|> String.replace "{{conditions}}" (conditions options.caseExpression items)
@ -276,3 +276,14 @@ conditions caseExpression items =
|> String.replace "{{result}}" (caseExpression.result name)
)
|> 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 Templates.Shared as Shared
contents : List Item -> String
contents items =
"""module Generated.Route exposing
contents : List Item -> List String -> String
contents items path =
"""module {{module_}} exposing
( Route(..)
, routes
, toPath
, {{exports}}
)
{-|
@docs Route
@docs routes
@docs toPath
-}
import Application.Route as Route
{{folderImports}}
@ -34,20 +27,19 @@ import Application.Route as Route
{{routeTypes}}
routes : List (Route.Route Route)
routes =
[ {{routes}}
]
toPath : Route -> String
toPath route =
case route of
{{toPath}}
"""
|> String.replace "{{module_}}" (module_ path)
|> String.replace "{{exports}}" (exports items)
|> String.replace "{{folderImports}}" (folderImports items)
|> String.replace "{{folderImports}}" (folderImports items path)
|> String.replace "{{fileParams}}" (fileParams items)
|> String.replace "{{folderParams}}" (folderParams items)
|> String.replace "{{routeTypes}}"
@ -62,6 +54,11 @@ toPath route =
|> String.replace "{{toPath}}" (toPath items)
module_ : List String -> String
module_ path =
"Generated.Route" ++ (path |> List.map ((++) ".") |> String.concat)
exports : List Item -> String
exports items =
items
@ -70,10 +67,20 @@ exports items =
|> String.join "\n , "
folderImports : List Item -> String
folderImports items =
folderImports : List Item -> List String -> String
folderImports items path =
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"
@ -121,17 +128,20 @@ routes items =
if name == "Index" then
"Route.index Index"
else if name == "Slug" then
"Route.slug Slug"
else
String.concat [ "Route.path \"", path name, "\" ", name ]
String.concat [ "Route.path \"", pathOf name, "\" ", name ]
)
, 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 , "
path : String -> String
path name =
pathOf : String -> String
pathOf name =
name
|> String.toList
|> List.map
@ -158,7 +168,7 @@ toPath items =
String.concat
[ name
, " _ ->\n \"/"
, path name
, pathOf name
, "\""
]
)
@ -168,7 +178,7 @@ toPath items =
String.concat
[ name
, " route_ ->\n \"/"
, path name
, pathOf name
, "\" ++ "
, name
, ".toPath route_"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
"build": "npm run build:example",
"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",
"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",
"keywords": [],

View File

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