diff --git a/.gitignore b/.gitignore index 39bedb3..2f93cb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store -dist +./dist elm-stuff/0.19.1 -example/elm-stuff/0.19.1 -node_modules \ No newline at end of file +./node_modules \ No newline at end of file diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 0000000..2111ae7 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1,3 @@ +dist +elm-stuff +node_modules \ No newline at end of file diff --git a/cli/README.md b/cli/README.md index 701fa31..2a05ec4 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,4 +1,4 @@ -# cli +# elm-spa/cli > the thing that types the stuff __Note:__ I will not implement this until I understand diff --git a/cli/elm.json b/cli/elm.json new file mode 100644 index 0000000..e8dfe90 --- /dev/null +++ b/cli/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src/elm" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.2", + "elm/html": "1.0.0", + "elm/json": "1.1.3" + }, + "indirect": { + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/cli/package-lock.json b/cli/package-lock.json new file mode 100644 index 0000000..aca883c --- /dev/null +++ b/cli/package-lock.json @@ -0,0 +1,403 @@ +{ + "name": "elm-spa", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "elm": { + "version": "0.19.1-3", + "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-3.tgz", + "integrity": "sha512-6y36ewCcVmTOx8lj7cKJs3bhI5qMfoVEigePZ9PhEUNKpwjjML/pU2u2YSpHVAznuCcojoF6KIsrS1Ci7GtVaQ==", + "dev": true, + "requires": { + "request": "^2.88.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", + "dev": true, + "requires": { + "mime-db": "1.42.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/cli/package.json b/cli/package.json new file mode 100644 index 0000000..2562693 --- /dev/null +++ b/cli/package.json @@ -0,0 +1,27 @@ +{ + "name": "elm-spa", + "version": "1.0.0", + "description": "the cli companion tool for ryannhg/elm-spa", + "main": "src/index.js", + "scripts": { + "start": "npm run build && node src/index.js", + "build": "npm run elm:compile", + "elm:compile": "elm make src/elm/Main.elm --output=dist/elm.compiled.js --optimize" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ryannhg/elm-spa.git" + }, + "keywords": [ + "elm", + "spa", + "cli", + "framework" + ], + "author": "Ryan Haskell-Glatz", + "license": "ISC", + "bugs": { + "url": "https://github.com/ryannhg/elm-spa/issues" + }, + "homepage": "https://github.com/ryannhg/elm-spa#readme" +} diff --git a/cli/src/elm/File.elm b/cli/src/elm/File.elm new file mode 100644 index 0000000..25ebd8b --- /dev/null +++ b/cli/src/elm/File.elm @@ -0,0 +1,106 @@ +module File exposing + ( File + , encode + , params + ) + +import Json.Encode as Json + + +type alias File = + { filepath : List String + , contents : String + } + + +encode : File -> Json.Value +encode file = + Json.object + [ ( "filepath", Json.list Json.string file.filepath ) + , ( "contents", Json.string file.contents ) + ] + + + +-- PARAMS TEMPLATE + + +params : + { moduleName : String + , paths : List (List String) + } + -> String +params options = + """ +module {{moduleName}} exposing (..) + + +{{paramsTypeAliases}} + """ + |> String.replace "{{moduleName}}" + (paramsModuleName options.moduleName) + |> String.replace "{{paramsTypeAliases}}" + (paramsTypeAliases options.paths) + |> String.trim + + +paramsModuleName : String -> String +paramsModuleName name = + [ "Generated", name, "Params" ] + |> List.filter (String.isEmpty >> not) + |> String.join "." + + +paramsTypeAliases : List (List String) -> String +paramsTypeAliases = + List.map paramsTypeAlias >> String.join "\n\n\n" + + +paramsTypeAlias : List String -> String +paramsTypeAlias filepath = + """ +type alias {{last}} = +{{paramsRecord}} + """ + |> String.replace "{{last}}" + (last filepath |> Maybe.withDefault "") + |> String.replace "{{paramsRecord}}" + (paramsRecord filepath |> indent 1) + |> String.trim + + +paramsRecord : List String -> String +paramsRecord path = + let + dynamicCount = + path + |> List.filter ((==) "Dynamic") + |> List.length + in + if dynamicCount < 1 then + "{}" + + else + List.range 1 dynamicCount + |> List.map String.fromInt + |> List.map (\num -> [ "param", num, " : String" ]) + |> List.map String.concat + |> String.join "\n, " + |> (\str -> "{ " ++ str ++ "\n}") + + + +-- UTILS + + +last : List a -> Maybe a +last list = + List.drop (List.length list - 1) list |> List.head + + +indent : Int -> String -> String +indent tabs str = + str + |> String.split "\n" + |> List.map (\s -> String.concat (List.repeat tabs " " ++ [ s ])) + |> String.join "\n" diff --git a/cli/src/elm/Main.elm b/cli/src/elm/Main.elm new file mode 100644 index 0000000..9e44607 --- /dev/null +++ b/cli/src/elm/Main.elm @@ -0,0 +1,77 @@ +module Main exposing (main) + +import Dict exposing (Dict) +import File exposing (File) +import Json.Encode as Json +import Ports + + +type alias Flags = + List Filepath + + +type alias Filepath = + List String + + +main : Program Flags () Never +main = + Platform.worker + { init = \json -> ( (), parse json ) + , update = \_ model -> ( model, Cmd.none ) + , subscriptions = always Sub.none + } + + + +-- ACTUAL CODE + + +parse : List Filepath -> Cmd msg +parse = + List.foldl groupByFolder Dict.empty + >> (\dict -> + [ paramsFiles dict + ] + ) + >> List.concat + >> Ports.sendFiles + + +folderOf : Filepath -> String +folderOf = + List.reverse + >> List.drop 1 + >> List.reverse + >> String.join "." + + +groupByFolder : + Filepath + -> Dict String (List Filepath) + -> Dict String (List Filepath) +groupByFolder items = + Dict.update + (folderOf items) + (Maybe.map ((::) items) + >> Maybe.withDefault [ items ] + >> Just + ) + + +paramsFiles : + Dict String (List Filepath) + -> List File +paramsFiles = + Dict.toList + >> List.map + (\( moduleName, paths ) -> + { filepath = + String.split "." moduleName ++ [ "Params" ] + , contents = + File.params + { moduleName = moduleName + , paths = paths + } + } + ) diff --git a/cli/src/elm/Ports.elm b/cli/src/elm/Ports.elm new file mode 100644 index 0000000..a58d1bc --- /dev/null +++ b/cli/src/elm/Ports.elm @@ -0,0 +1,19 @@ +port module Ports exposing (sendFiles) + +import File exposing (File) +import Json.Encode as Json + + +port outgoing : + { message : String + , data : Json.Value + } + -> Cmd msg + + +sendFiles : List File -> Cmd msg +sendFiles files = + outgoing + { message = "sendFiles" + , data = Json.list File.encode files + } diff --git a/cli/src/index.js b/cli/src/index.js new file mode 100644 index 0000000..a1a95e9 --- /dev/null +++ b/cli/src/index.js @@ -0,0 +1,11 @@ +const path = require('path') +const cwd = process.cwd() +const { File, Elm } = require('./utils.js') + +const start = () => + File.paths(path.join(cwd, '..', 'examples', 'complex', 'src', 'Pages')) + .then(Elm.run) + .then(console.info) + .catch(console.error) + +start(process.argv.slice(2)) \ No newline at end of file diff --git a/cli/src/utils.js b/cli/src/utils.js new file mode 100644 index 0000000..2586ec4 --- /dev/null +++ b/cli/src/utils.js @@ -0,0 +1,87 @@ +const File = (_ => { + const path = require('path') + const fs = require('fs') + + const mkdir = (filepath) => + new Promise((resolve, reject) => + fs.mkdir(filepath, { recursive: true }, (err) => err ? reject(err) : resolve(filepath)) + ) + + const create = (filepath, contents) => { + const write = (filepath, contents) => + new Promise((resolve, reject) => + fs.writeFile(filepath, contents, { encoding: 'utf8' }, (err) => + err ? reject(err) : resolve(filepath) + ) + ) + + return fs.existsSync(folderOf(filepath)) + ? write(filepath, contents) + : mkdir(folderOf(filepath)).then(_ => write(filepath, contents)) + } + + const paths = (filepath) => { + const ls = (filepath) => + new Promise((resolve, reject) => + fs.readdir(filepath, (err, files) => + err ? reject(err) : resolve(files)) + ) + + const reduce = (fn, init) => (items) => + items.reduce(fn, init) + + const concat = (a, b) => + a.concat(b) + + const all = (fn) => (items) => + Promise.all(items.map(fn)) + + const isFile = (name) => + name.indexOf('.') > -1 + + const toPath = (filepath) => (name) => + isFile(name) + ? Promise.resolve([[ name.split('.')[0] ]]) + : paths(path.join(filepath, name)) + .then(files => files.map(file => [ name ].concat(file))) + + return ls(filepath) + .then(all(toPath(filepath))) + .then(reduce(concat, [])) + } + + return { + paths, + mkdir, + create + } +})() + +const Elm = (_ => { + const { Elm } = require('../dist/elm.compiled.js') + + const handlers = { + sendFiles: (data) => + data.forEach(a => console.log(a.filepath) || console.log(a.contents)) + } + + const run = paths => + new Promise((resolve, reject) => { + const app = Elm.Main.init({ flags: paths }) + + app.ports.outgoing.subscribe(({ message, data }) => + handlers[message] + ? Promise.resolve(handlers[message](data)).then(resolve).catch(reject) + : reject(`Didn't recognize message "${message}"– Yell at @ryannhg on the internet!\n`) + ) + }) + + return { + run + } +})() + +module.exports = { + Elm, + File +} \ No newline at end of file diff --git a/example/README.md b/example/README.md deleted file mode 100644 index 72e864c..0000000 --- a/example/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# elm-spa/example -> what a project might look like! - - -## running things - -``` -npm install -npm run dev -``` \ No newline at end of file diff --git a/example/elm-stuff/.elm-spa/README.md b/example/elm-stuff/.elm-spa/README.md deleted file mode 100644 index 5d49a3a..0000000 --- a/example/elm-stuff/.elm-spa/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# elm-stuff/.elm-spa -> this is where all the generated code goes! - -Normally, this whole directory should be `.gitignore`d, -but I'm keeping it around so I can better understand -what `elm-spa build` should be generating! diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..f8964f6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,10 @@ +# elm-spa/examples +> example projects using elm-spa + +### how do I get started? + +Check out the [intro example](./intro) to see what a project looks like. + +### how does elm-spa handle XYZ? + +There's a more [complex example](./complex) to answer those questions. diff --git a/example/.gitignore b/examples/complex/.gitignore similarity index 77% rename from example/.gitignore rename to examples/complex/.gitignore index a4be2e2..088b52a 100644 --- a/example/.gitignore +++ b/examples/complex/.gitignore @@ -1,3 +1,4 @@ +.DS_Store dist elm-stuff/0.19.1 node_modules \ No newline at end of file diff --git a/examples/complex/README.md b/examples/complex/README.md new file mode 100644 index 0000000..95d8599 --- /dev/null +++ b/examples/complex/README.md @@ -0,0 +1,10 @@ +# elm-spa/examples/complex +> an example of using more complex features + + +## running things + +``` +npm install +npm run dev +``` \ No newline at end of file diff --git a/example/elm-stuff/.elm-spa/Generated/Docs/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Docs/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Docs/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Docs/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Docs/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Docs/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Docs/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Docs/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Docs/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Docs/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Docs/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Docs/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Dynamic/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Faq/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Dynamic/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Guide/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Guide/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Guide/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Guide/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Pages.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Pages.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Pages.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Pages.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Params.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Params.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Params.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Params.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Route.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Route.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Route.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Route.elm diff --git a/example/elm-stuff/.elm-spa/Generated/Routes.elm b/examples/complex/elm-stuff/.elm-spa/Generated/Routes.elm similarity index 100% rename from example/elm-stuff/.elm-spa/Generated/Routes.elm rename to examples/complex/elm-stuff/.elm-spa/Generated/Routes.elm diff --git a/examples/complex/elm-stuff/.elm-spa/README.md b/examples/complex/elm-stuff/.elm-spa/README.md new file mode 100644 index 0000000..437568e --- /dev/null +++ b/examples/complex/elm-stuff/.elm-spa/README.md @@ -0,0 +1,6 @@ +# elm-stuff/.elm-spa +> this is where all the generated code goes! + +Normally, this whole directory should __not__ be in `git`, +but I'm keeping it around for now to better understand +all the edge cases that the CLI should generate! diff --git a/example/elm.json b/examples/complex/elm.json similarity index 97% rename from example/elm.json rename to examples/complex/elm.json index b764cce..97ed1ab 100644 --- a/example/elm.json +++ b/examples/complex/elm.json @@ -2,7 +2,7 @@ "type": "application", "source-directories": [ "src", - "../src", + "../../src", "elm-stuff/.elm-spa" ], "elm-version": "0.19.1", diff --git a/example/index.html b/examples/complex/index.html similarity index 100% rename from example/index.html rename to examples/complex/index.html diff --git a/example/package-lock.json b/examples/complex/package-lock.json similarity index 99% rename from example/package-lock.json rename to examples/complex/package-lock.json index db291e5..6d25b43 100644 --- a/example/package-lock.json +++ b/examples/complex/package-lock.json @@ -1,5 +1,5 @@ { - "name": "elm-spa-elm-ui", + "name": "complex-elm-spa-example", "version": "1.0.0", "lockfileVersion": 1, "requires": true, diff --git a/example/package.json b/examples/complex/package.json similarity index 95% rename from example/package.json rename to examples/complex/package.json index 83fcb01..f764e93 100644 --- a/example/package.json +++ b/examples/complex/package.json @@ -1,5 +1,5 @@ { - "name": "your-elm-spa", + "name": "complex-elm-spa-example", "version": "1.0.0", "description": "an example for elm-spa!", "main": "src/index.js", diff --git a/example/public/ports.js b/examples/complex/public/ports.js similarity index 100% rename from example/public/ports.js rename to examples/complex/public/ports.js diff --git a/example/public/styles.css b/examples/complex/public/styles.css similarity index 100% rename from example/public/styles.css rename to examples/complex/public/styles.css diff --git a/example/src/Components/Button.elm b/examples/complex/src/Components/Button.elm similarity index 100% rename from example/src/Components/Button.elm rename to examples/complex/src/Components/Button.elm diff --git a/example/src/Components/Hero.elm b/examples/complex/src/Components/Hero.elm similarity index 100% rename from example/src/Components/Hero.elm rename to examples/complex/src/Components/Hero.elm diff --git a/example/src/Components/Section.elm b/examples/complex/src/Components/Section.elm similarity index 100% rename from example/src/Components/Section.elm rename to examples/complex/src/Components/Section.elm diff --git a/example/src/Components/Styles.elm b/examples/complex/src/Components/Styles.elm similarity index 100% rename from example/src/Components/Styles.elm rename to examples/complex/src/Components/Styles.elm diff --git a/example/src/Global.elm b/examples/complex/src/Global.elm similarity index 100% rename from example/src/Global.elm rename to examples/complex/src/Global.elm diff --git a/example/src/Layout.elm b/examples/complex/src/Layout.elm similarity index 100% rename from example/src/Layout.elm rename to examples/complex/src/Layout.elm diff --git a/example/src/Layouts/Docs.elm b/examples/complex/src/Layouts/Docs.elm similarity index 100% rename from example/src/Layouts/Docs.elm rename to examples/complex/src/Layouts/Docs.elm diff --git a/example/src/Layouts/Guide.elm b/examples/complex/src/Layouts/Guide.elm similarity index 100% rename from example/src/Layouts/Guide.elm rename to examples/complex/src/Layouts/Guide.elm diff --git a/example/src/Layouts/Guide/Dynamic.elm b/examples/complex/src/Layouts/Guide/Dynamic.elm similarity index 100% rename from example/src/Layouts/Guide/Dynamic.elm rename to examples/complex/src/Layouts/Guide/Dynamic.elm diff --git a/example/src/Layouts/Guide/Dynamic/Dynamic.elm b/examples/complex/src/Layouts/Guide/Dynamic/Dynamic.elm similarity index 100% rename from example/src/Layouts/Guide/Dynamic/Dynamic.elm rename to examples/complex/src/Layouts/Guide/Dynamic/Dynamic.elm diff --git a/example/src/Layouts/Guide/Dynamic/Faq.elm b/examples/complex/src/Layouts/Guide/Dynamic/Faq.elm similarity index 100% rename from example/src/Layouts/Guide/Dynamic/Faq.elm rename to examples/complex/src/Layouts/Guide/Dynamic/Faq.elm diff --git a/example/src/Main.elm b/examples/complex/src/Main.elm similarity index 100% rename from example/src/Main.elm rename to examples/complex/src/Main.elm diff --git a/example/src/Pages/Docs.elm b/examples/complex/src/Pages/Docs.elm similarity index 100% rename from example/src/Pages/Docs.elm rename to examples/complex/src/Pages/Docs.elm diff --git a/example/src/Pages/Docs/Dynamic.elm b/examples/complex/src/Pages/Docs/Dynamic.elm similarity index 100% rename from example/src/Pages/Docs/Dynamic.elm rename to examples/complex/src/Pages/Docs/Dynamic.elm diff --git a/example/src/Pages/Docs/Static.elm b/examples/complex/src/Pages/Docs/Static.elm similarity index 100% rename from example/src/Pages/Docs/Static.elm rename to examples/complex/src/Pages/Docs/Static.elm diff --git a/example/src/Pages/Guide.elm b/examples/complex/src/Pages/Guide.elm similarity index 100% rename from example/src/Pages/Guide.elm rename to examples/complex/src/Pages/Guide.elm diff --git a/example/src/Pages/Guide/Dynamic/Dynamic.elm b/examples/complex/src/Pages/Guide/Dynamic/Dynamic.elm similarity index 100% rename from example/src/Pages/Guide/Dynamic/Dynamic.elm rename to examples/complex/src/Pages/Guide/Dynamic/Dynamic.elm diff --git a/example/src/Pages/Guide/Dynamic/Dynamic/Top.elm b/examples/complex/src/Pages/Guide/Dynamic/Dynamic/Top.elm similarity index 100% rename from example/src/Pages/Guide/Dynamic/Dynamic/Top.elm rename to examples/complex/src/Pages/Guide/Dynamic/Dynamic/Top.elm diff --git a/example/src/Pages/Guide/Dynamic/Faq/Top.elm b/examples/complex/src/Pages/Guide/Dynamic/Faq/Top.elm similarity index 100% rename from example/src/Pages/Guide/Dynamic/Faq/Top.elm rename to examples/complex/src/Pages/Guide/Dynamic/Faq/Top.elm diff --git a/example/src/Pages/Guide/Dynamic/Intro.elm b/examples/complex/src/Pages/Guide/Dynamic/Intro.elm similarity index 100% rename from example/src/Pages/Guide/Dynamic/Intro.elm rename to examples/complex/src/Pages/Guide/Dynamic/Intro.elm diff --git a/example/src/Pages/Guide/Dynamic/Other.elm b/examples/complex/src/Pages/Guide/Dynamic/Other.elm similarity index 100% rename from example/src/Pages/Guide/Dynamic/Other.elm rename to examples/complex/src/Pages/Guide/Dynamic/Other.elm diff --git a/example/src/Pages/Guide/Elm.elm b/examples/complex/src/Pages/Guide/Elm.elm similarity index 100% rename from example/src/Pages/Guide/Elm.elm rename to examples/complex/src/Pages/Guide/Elm.elm diff --git a/example/src/Pages/Guide/ElmSpa.elm b/examples/complex/src/Pages/Guide/ElmSpa.elm similarity index 100% rename from example/src/Pages/Guide/ElmSpa.elm rename to examples/complex/src/Pages/Guide/ElmSpa.elm diff --git a/example/src/Pages/Guide/Programming.elm b/examples/complex/src/Pages/Guide/Programming.elm similarity index 100% rename from example/src/Pages/Guide/Programming.elm rename to examples/complex/src/Pages/Guide/Programming.elm diff --git a/example/src/Pages/NotFound.elm b/examples/complex/src/Pages/NotFound.elm similarity index 100% rename from example/src/Pages/NotFound.elm rename to examples/complex/src/Pages/NotFound.elm diff --git a/example/src/Pages/SignIn.elm b/examples/complex/src/Pages/SignIn.elm similarity index 100% rename from example/src/Pages/SignIn.elm rename to examples/complex/src/Pages/SignIn.elm diff --git a/example/src/Pages/Top.elm b/examples/complex/src/Pages/Top.elm similarity index 100% rename from example/src/Pages/Top.elm rename to examples/complex/src/Pages/Top.elm diff --git a/example/src/Ports.elm b/examples/complex/src/Ports.elm similarity index 100% rename from example/src/Ports.elm rename to examples/complex/src/Ports.elm diff --git a/example/src/Utils/Spa.elm b/examples/complex/src/Utils/Spa.elm similarity index 57% rename from example/src/Utils/Spa.elm rename to examples/complex/src/Utils/Spa.elm index a418e29..6e7bed5 100644 --- a/example/src/Utils/Spa.elm +++ b/examples/complex/src/Utils/Spa.elm @@ -34,18 +34,23 @@ type alias Bundle msg appMsg = App.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) -layout config = - App.Page.layout - { map = Element.map - , view = config.view - , recipe = config.recipe - } +type alias Layout params model msg appMsg = + App.Types.Layout params model msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) -recipe config = - App.Page.recipe - { map = Element.map - , page = config.page - , toModel = config.toModel - , toMsg = config.toMsg - } +type alias Upgrade params model msg layoutModel layoutMsg appMsg = + App.Types.Upgrade params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg) + + +layout : + Layout params model msg appMsg + -> Page params model msg layoutModel layoutMsg appMsg +layout = + App.Page.layout Element.map + + +recipe : + Upgrade params model msg layoutModel layoutMsg appMsg + -> Recipe params model msg layoutModel layoutMsg appMsg +recipe = + App.Page.recipe Element.map diff --git a/package.json b/package.json index 69f194e..ffb7023 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,14 @@ "name": "elm-spa", "version": "1.0.0", "description": "", - "main": "src/index.js", + "main": "cli/src/index.js", "scripts": { "start": "npm run dev", - "example": "npm run dev", - "dev": "(cd example && npm install && npm run dev)" + "build": "(cd cli && npm run build)", + "dev": "npm run example", + "example": "npm run examples:complex", + "examples:intro": "(cd examples/intro && npm install && npm run dev)", + "examples:complex": "(cd examples/complex && npm install && npm run dev)" }, "dependencies": {}, "devDependencies": {}, diff --git a/src/App.elm b/src/App.elm index 8d4d587..0f35197 100644 --- a/src/App.elm +++ b/src/App.elm @@ -14,12 +14,10 @@ as the entrypoint to your app. module Main exposing (main) import App - import Element import Global import Pages import Routes - main : App.Program Global.Flags Global.Model Global.Msg Pages.Model Pages.Msg main = App.create { ui = App.usingHtml @@ -140,11 +138,10 @@ create : create config = let page = - Page.upgrade + Page.upgrade (always identity) { toModel = identity , toMsg = identity , page = config.page - , map = always identity } in Browser.application diff --git a/src/App/Page.elm b/src/App/Page.elm index f842344..2fd3de1 100644 --- a/src/App/Page.elm +++ b/src/App/Page.elm @@ -61,36 +61,11 @@ these are for! ## layout -A page that is comprimised of smaller pages, that is -able to share a common layout (maybe a something like a sidebar!) - - page = - Page.layout - { map = Html.map - , layout = Layout.view - , pages = - { init = init - , update = update - , bundle = bundle - } - } - @docs layout ## recipe -Implementing the `init`, `update` and `bundle` functions is much easier -when you turn a `Page` type into `Recipe`. - -A `Recipe` contains a record waiting for page specific data. - - - `init`: just needs a `route` - - - `upgrade` : just needs a `msg` and `model` - - - `bundle` (`view`/`subscriptions`) : just needs a `model` - @docs recipe @@ -151,36 +126,41 @@ type alias Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui Internals.Page.Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -{-| Turns a page and some upgrade information into a recipe, -for use in a layout's `init`, `update`, and `bundle` functions! +{-| Implementing the `init`, `update` and `bundle` functions is much easier +when you turn a `Page` type into `Recipe`. - import Utils.Spa as Spa +A `Recipe` contains a record waiting for page specific data. - recipes : Recipes msg - recipes = - { top = - Spa.recipe - { page = Top.page - , toModel = TopModel - , toMsg = TopMsg - } - , counter = - Spa.recipe - { page = Counter.page - , toModel = CounterModel - , toMsg = CounterMsg - } + - `init`: just needs a `route` - -- ... - } + - `upgrade` : just needs a `msg` and `model` + + - `bundle` (`view`/`subscriptions`) : just needs a `model` + + import Utils.Spa as Spa + + recipes : Recipes msg + recipes = + { top = + Spa.recipe + { page = Top.page + , toModel = TopModel + , toMsg = TopMsg + } + , counter = + Spa.recipe + { page = Counter.page + , toModel = CounterModel + , toMsg = CounterMsg + } + + -- ... + } -} recipe : - { page : Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg - , toModel : pageModel -> layoutModel - , toMsg : pageMsg -> layoutMsg - , map : (pageMsg -> layoutMsg) -> ui_pageMsg -> ui_layoutMsg - } + ((pageMsg -> layoutMsg) -> ui_pageMsg -> ui_layoutMsg) + -> Upgrade pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -> Recipe pageParams pageModel pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg recipe = Internals.Page.upgrade @@ -508,17 +488,10 @@ send = -} layout : - { map : (pageMsg -> msg) -> ui_pageMsg -> ui_msg - , view : - { page : ui_msg - , global : globalModel - , toMsg : globalMsg -> msg - } - -> ui_msg - , recipe : Recipe pageParams pageModel pageMsg pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg - } + ((pageMsg -> msg) -> ui_pageMsg -> ui_msg) + -> Layout pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg -> Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -layout options = +layout map options = Page (\{ toModel, toMsg } -> { init = @@ -539,7 +512,7 @@ layout options = { fromGlobalMsg = context.fromGlobalMsg , fromPageMsg = toMsg >> context.fromPageMsg , global = context.global - , map = options.map + , map = map } in { title = bundle.title diff --git a/src/App/Types.elm b/src/App/Types.elm index fcc541e..88ba92d 100644 --- a/src/App/Types.elm +++ b/src/App/Types.elm @@ -4,6 +4,7 @@ module App.Types exposing , Init , Update , Bundle + , Layout, Upgrade ) {-| @@ -48,6 +49,11 @@ doing things by hand. @docs Bundle + +# layouts and recipes + +@docs Layout, Upgrade + -} import Internals.Page as Page @@ -225,3 +231,83 @@ type alias Update layoutModel layoutMsg globalModel globalMsg = -} type alias Bundle layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = Page.Bundle layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg + + +{-| + + +## creating your alias + +**`src/Utils/Spa.elm`** + + -- if using mdgriffith/elm-ui + + import App.Types + import Element exposing (Element) + + type alias Bundle msg appMsg = + App.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) + + -- if using elm/html + + import App.Types + import Html exposing (Html) + + type alias Bundle msg appMsg = + App.Types.Bundle msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg) + + +## using your alias + +**`.elm-spa/Generated/Pages.elm`** + + import Utils.Spa as Spa + + bundle : Model -> Spa.Bundle Msg msg + bundle model_ = + case model_ of + -- ... + +-} +type alias Layout pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg = + Page.Layout pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg + + +{-| + + +## creating your alias + +**`src/Utils/Spa.elm`** + + -- if using mdgriffith/elm-ui + + import App.Types + import Element exposing (Element) + + type alias Bundle msg appMsg = + App.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) + + -- if using elm/html + + import App.Types + import Html exposing (Html) + + type alias Bundle msg appMsg = + App.Types.Bundle msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg) + + +## using your alias + +**`.elm-spa/Generated/Pages.elm`** + + import Utils.Spa as Spa + + bundle : Model -> Spa.Bundle Msg msg + bundle model_ = + case model_ of + -- ... + +-} +type alias Upgrade pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = + Page.Upgrade pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg diff --git a/src/Internals/Page.elm b/src/Internals/Page.elm index 1aa19f1..e7fe36f 100644 --- a/src/Internals/Page.elm +++ b/src/Internals/Page.elm @@ -1,15 +1,14 @@ module Internals.Page exposing ( Bundle , Init + , Layout , Page(..) , Recipe , Update + , Upgrade , upgrade ) -{-| Page docs --} - type Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = Page (Page_ pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg) @@ -23,8 +22,6 @@ type alias Page_ pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg u -> Recipe pageParams pageModel pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -{-| Recipe docs --} type alias Recipe pageParams pageModel pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = { init : pageParams -> Init layoutModel layoutMsg globalModel globalMsg , update : pageMsg -> pageModel -> Update layoutModel layoutMsg globalModel globalMsg @@ -32,14 +29,18 @@ type alias Recipe pageParams pageModel pageMsg layoutModel layoutMsg ui_layoutMs } -upgrade : +type alias Upgrade pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = { page : Page pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg , toModel : pageModel -> layoutModel , toMsg : pageMsg -> layoutMsg - , map : (pageMsg -> layoutMsg) -> ui_pageMsg -> ui_layoutMsg } + + +upgrade : + ((pageMsg -> layoutMsg) -> ui_pageMsg -> ui_layoutMsg) + -> Upgrade pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -> Recipe pageParams pageModel pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg -upgrade config = +upgrade map config = let (Page page) = config.page @@ -47,26 +48,20 @@ upgrade config = page { toModel = config.toModel , toMsg = config.toMsg - , map = config.map + , map = map } -{-| Init docs --} type alias Init layoutModel layoutMsg globalModel globalMsg = { global : globalModel } -> ( layoutModel, Cmd layoutMsg, Cmd globalMsg ) -{-| Update docs --} type alias Update layoutModel layoutMsg globalModel globalMsg = { global : globalModel } -> ( layoutModel, Cmd layoutMsg, Cmd globalMsg ) -{-| Bundle docs --} type alias Bundle layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = { global : globalModel , fromGlobalMsg : globalMsg -> msg @@ -78,3 +73,14 @@ type alias Bundle layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = , view : ui_msg , subscriptions : Sub msg } + + +type alias Layout pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg = + { view : + { page : ui_msg + , global : globalModel + , toMsg : globalMsg -> msg + } + -> ui_msg + , recipe : Recipe pageParams pageModel pageMsg pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg + }