Move stuff

This commit is contained in:
Richard Feldman
2018-08-05 04:13:33 -04:00
parent bf20622319
commit 7793c69762
3419 changed files with 6 additions and 7 deletions

View File

@@ -0,0 +1 @@
elm-stuff

View File

@@ -0,0 +1,30 @@
Copyright (c) 2014, Evan Czaplicki
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Evan Czaplicki nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,38 @@
# Markdown in Elm
This package is for markdown parsing and rendering. It is based on the [marked][] project
which focuses on speed.
[marked]: https://github.com/chjj/marked
## Basic Usage
```elm
content : Html msg
content =
Markdown.toHtml [class "content"] """
# Apple Pie Recipe
1. Invent the universe.
2. Bake an apple pie.
"""
```
**Warning:** Calling `Markdown.toHtml` parses the whole block, so try not to
call it for no reason. In the `content` example above we only have to parse
the text once, but if we put it in a function we may be doing a lot of
unnecessary parsing.
## Code Blocks
For highlighting any code blocks, the package relies on the
[highlight.js](https://highlightjs.org/) project. So if you want to
see highlighting of code blocks in the rendering result, you need to
make sure that your page/app binds a version of that library
(supporting the languages you want to handle) to `window.hljs` in
Javascript. [This is how package.elm-lang.org does
that.](https://github.com/elm-lang/package.elm-lang.org/blob/e0b7aa4282038475612722ff7a57195866f8645b/backend/ServeFile.hs#L54)

View File

@@ -0,0 +1,18 @@
{
"version": "3.0.2",
"summary": "Fast markdown parsing and rendering",
"repository": "https://github.com/evancz/elm-markdown.git",
"license": "BSD3",
"source-directories": [
"src"
],
"exposed-modules": [
"Markdown"
],
"native-modules": true,
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,104 @@
module Markdown exposing
( toHtml
, Options, defaultOptions, toHtmlWith
)
{-| A library for markdown parsing. This is just an Elm API built on top of the
[marked](https://github.com/chjj/marked) project which focuses on speed.
# Parsing Markdown
@docs toHtml
# Parsing with Custom Options
@docs Options, defaultOptions, toHtmlWith
-}
import Html exposing (Html, Attribute)
import Native.Markdown
{-| Turn a markdown string into an HTML element, using the `defaultOptions`.
recipe : Html msg
recipe =
Markdown.toHtml [class "recipe"] """
# Apple Pie Recipe
First, invent the universe. Then bake an apple pie.
"""
-}
toHtml : List (Attribute msg) -> String -> Html msg
toHtml attrs string =
Native.Markdown.toHtml defaultOptions attrs string
{-| Some parser options so you can tweak things for your particular case.
* `githubFlavored` &mdash; overall reasonable improvements on the original
markdown parser as described [here][gfm]. This includes stuff like [fenced
code blocks][fenced]. There are some odd parts though, such as [tables][]
and a setting to turn all newlines into newlines in the resulting output,
so there are settings to turn those on or off based on your preference.
* `defaultHighlighting` &mdash; a default language to use for code blocks that do
not have a language tag. So setting this to `Just "elm"` will treat all
unlabeled code blocks as Elm code. (This relies on [highlight.js][highlight]
as explained in the README [here](../#code-blocks).)
* `sanitize` &mdash; this determines if all HTML should be escaped. If you
are parsing user markdown or user input can somehow reach the markdown
parser, you should almost certainly turn on sanitation. If it is just you
writing markdown, turning sanitation off is a nice way to do some HTML
tricks if it is needed.
* `smartypants` &mdash; This will automatically upgrade quotes to the
prettier versions and turn dashes into [em dashes or en dashes][dash]
[gfm]: https://help.github.com/articles/github-flavored-markdown/
[fenced]: https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks
[tables]: https://help.github.com/articles/github-flavored-markdown/#tables
[highlight]: https://highlightjs.org/
[dash]: http://en.wikipedia.org/wiki/Dash
-}
type alias Options =
{ githubFlavored : Maybe { tables : Bool, breaks : Bool }
, defaultHighlighting : Maybe String
, sanitize : Bool
, smartypants : Bool
}
{-| The `Options` used by the `toElement` and `toHtml` functions.
{ githubFlavored = Just { tables = False, breaks = False }
, defaultHighlighting = Nothing
, sanitize = False
, smartypants = False
}
-}
defaultOptions : Options
defaultOptions =
{ githubFlavored = Just { tables = False, breaks = False }
, defaultHighlighting = Nothing
, sanitize = False
, smartypants = False
}
{-| Maybe you want to parse user input into markdown. To stop them from adding
`<script>` tags, you can use modified parsing options.
options : Options
options =
{ defaultOptions | sanitize = True }
toMarkdown : String -> Html
toMarkdown userInput =
Markdown.toHtmlWith options [] userInput
-}
toHtmlWith : Options -> List (Attribute msg) -> String -> Html msg
toHtmlWith =
Native.Markdown.toHtml

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
elm-stuff

View File

@@ -0,0 +1,27 @@
Copyright (c) 2016, Evan Czaplicki
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,67 @@
# URL Parser
This library helps you turn URLs into nicely structured data.
It is designed to be used with `elm-lang/navigation` to help folks create single-page applications (SPAs) where you manage browser navigation yourself.
> **Note:** This library is meant to serve as a baseline for future URL parsers. For example, it does not handle query parameters and hashes right now. It is more to (1) get folks started using URL parsers and (2) help us gather data on exactly which scenarios people face.
## Examples
Here is a simplified REPL session showing a parser in action:
```elm
> import UrlParser exposing ((</>), s, int, string, parseHash)
> parseHash (s "blog" </> int) { ... , hash = "#blog/42" }
Just 42
> parseHash (s "blog" </> int) { ... , hash = "#/blog/13" }
Just 13
> parseHash (s "blog" </> int) { ... , hash = "#/blog/hello" }
Nothing
> parseHash (s "search" </> string) { ... , hash = "#search/dogs" }
Just "dogs"
> parseHash (s "search" </> string) { ... , hash = "#/search/13" }
Just "13"
> parseHash (s "search" </> string) { ... , hash = "#/search" }
Nothing
```
Normally you have to put many of these parsers to handle all possible pages though! The following parser works on URLs like `/blog/42` and `/search/badger`:
```elm
import UrlParser exposing (Parser, (</>), s, int, string, map, oneOf, parseHash)
type Route = Blog Int | Search String
route : Parser (Route -> a) a
route =
oneOf
[ map Blog (s "blog" </> int)
, map Search (s "search" </> string)
]
-- parseHash route { ... , hash = "#/blog/58" } == Just (Blog 58)
-- parseHash route { ... , hash = "#/search/cat" } == Just (Search "cat")
-- parseHash route { ... , hash = "#/search/31" } == Just (Search "31")
-- parseHash route { ... , hash = "#/blog/cat" } == Nothing
-- parseHash route { ... , hash = "#/blog" } == Nothing
```
Notice that we are turning URLs into nice [union types](https://guide.elm-lang.org/types/union_types.html), so we can use `case` expressions to work with them in a nice way.
Check out the `examples/` directory of this repo to see this in use with `elm-lang/navigation`.
## Background
I first saw this general idea in Chris Done&rsquo;s [formatting][] library. Based on that, Noah and I outlined the API you see in this library. Noah then found Rudi Grinberg&rsquo;s [post][] about type safe routing in OCaml. It was exactly what we were going for. We had even used the names `s` and `(</>)` in our draft API! In the end, we ended up using the &ldquo;final encoding&rdquo; of the EDSL that had been left as an exercise for the reader. Very fun to work through!
[formatting]: http://chrisdone.com/posts/formatting
[post]: http://rgrinberg.com/posts/primitive-type-safe-routing/

View File

@@ -0,0 +1,18 @@
{
"version": "2.0.1",
"summary": "Parse URLs into nicely structured data, useful for navigation / \"SPA routing\"",
"repository": "https://github.com/evancz/url-parser.git",
"license": "BSD3",
"source-directories": [
"src"
],
"exposed-modules": [
"UrlParser"
],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/http": "1.0.0 <= v < 2.0.0",
"elm-lang/navigation": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,128 @@
import Html exposing (Html, a, button, code, div, h1, li, text, ul)
import Html.Attributes exposing (href)
import Html.Events exposing (onClick)
import Http
import Navigation
import UrlParser as Url exposing ((</>), (<?>), s, int, stringParam, top)
main =
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ history : List (Maybe Route)
}
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
( Model [Url.parsePath route location]
, Cmd.none
)
-- URL PARSING
type Route
= Home
| BlogList (Maybe String)
| BlogPost Int
route : Url.Parser (Route -> a) a
route =
Url.oneOf
[ Url.map Home top
, Url.map BlogList (s "blog" <?> stringParam "search")
, Url.map BlogPost (s "blog" </> int)
]
-- UPDATE
type Msg
= NewUrl String
| UrlChange Navigation.Location
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NewUrl url ->
( model
, Navigation.newUrl url
)
UrlChange location ->
( { model | history = Url.parsePath route location :: model.history }
, Cmd.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
div []
[ h1 [] [ text "Links" ]
, ul [] (List.map viewLink [ "/", "/blog/", "/blog/42", "/blog/37", "/blog/?search=cats" ])
, h1 [] [ text "History" ]
, ul [] (List.map viewRoute model.history)
]
viewLink : String -> Html Msg
viewLink url =
li [] [ button [ onClick (NewUrl url) ] [ text url ] ]
viewRoute : Maybe Route -> Html msg
viewRoute maybeRoute =
case maybeRoute of
Nothing ->
li [] [ text "Invalid URL"]
Just route ->
li [] [ code [] [ text (routeToString route) ] ]
routeToString : Route -> String
routeToString route =
case route of
Home ->
"home"
BlogList Nothing ->
"list all blog posts"
BlogList (Just search) ->
"search for " ++ Http.encodeUri search
BlogPost id ->
"show blog " ++ toString id

View File

@@ -0,0 +1,12 @@
# Run the Examples
To run the examples in this folder, follow the following steps:
```bash
git clone https://github.com/evancz/url-parser.git
cd url-parser
cd examples
elm-reactor
```
This will navigate into the `examples/` directory and start `elm-reactor`. From here, go to [http://localhost:8000](http://localhost:8000) and start clicking on `.elm` files to see them in action.

View File

@@ -0,0 +1,18 @@
{
"version": "1.0.0",
"summary": "Examples of using evancz/url-parser",
"repository": "http://github.com/user/project.git",
"license": "BSD-3-Clause",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/http": "1.0.0 <= v < 2.0.0",
"elm-lang/navigation": "2.0.0 <= v < 3.0.0",
"evancz/url-parser": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,414 @@
module UrlParser exposing
( Parser, string, int, s
, (</>), map, oneOf, top, custom
, QueryParser, (<?>), stringParam, intParam, customParam
, parsePath, parseHash
)
{-|
# Primitives
@docs Parser, string, int, s
# Path Parses
@docs (</>), map, oneOf, top, custom
# Query Parameter Parsers
@docs QueryParser, (<?>), stringParam, intParam, customParam
# Run a Parser
@docs parsePath, parseHash
-}
import Dict exposing (Dict)
import Http
import Navigation
-- PARSERS
{-| Turn URLs like `/blog/42/cat-herding-techniques` into nice Elm data.
-}
type Parser a b =
Parser (State a -> List (State b))
type alias State value =
{ visited : List String
, unvisited : List String
, params : Dict String String
, value : value
}
-- PARSE SEGMENTS
{-| Parse a segment of the path as a `String`.
parsePath string location
-- /alice/ ==> Just "alice"
-- /bob ==> Just "bob"
-- /42/ ==> Just "42"
-}
string : Parser (String -> a) a
string =
custom "STRING" Ok
{-| Parse a segment of the path as an `Int`.
parsePath int location
-- /alice/ ==> Nothing
-- /bob ==> Nothing
-- /42/ ==> Just 42
-}
int : Parser (Int -> a) a
int =
custom "NUMBER" String.toInt
{-| Parse a segment of the path if it matches a given string.
s "blog" -- can parse /blog/
-- but not /glob/ or /42/ or anything else
-}
s : String -> Parser a a
s str =
Parser <| \{ visited, unvisited, params, value } ->
case unvisited of
[] ->
[]
next :: rest ->
if next == str then
[ State (next :: visited) rest params value ]
else
[]
{-| Create a custom path segment parser. Here is how it is used to define the
`int` and `string` parsers:
int =
custom "NUMBER" String.toInt
string =
custom "STRING" Ok
You can use it to define something like only CSS files like this:
css : Parser (String -> a) a
css =
custom "CSS_FILE" <| \segment ->
if String.endsWith ".css" then
Ok segment
else
Err "Does not end with .css"
-}
custom : String -> (String -> Result String a) -> Parser (a -> b) b
custom tipe stringToSomething =
Parser <| \{ visited, unvisited, params, value } ->
case unvisited of
[] ->
[]
next :: rest ->
case stringToSomething next of
Ok nextValue ->
[ State (next :: visited) rest params (value nextValue) ]
Err msg ->
[]
-- COMBINING PARSERS
{-| Parse a path with multiple segments.
parsePath (s "blog" </> int) location
-- /blog/35/ ==> Just 35
-- /blog/42 ==> Just 42
-- /blog/ ==> Nothing
-- /42/ ==> Nothing
parsePath (s "search" </> string) location
-- /search/cats/ ==> Just "cats"
-- /search/frog ==> Just "frog"
-- /search/ ==> Nothing
-- /cats/ ==> Nothing
-}
(</>) : Parser a b -> Parser b c -> Parser a c
(</>) (Parser parseBefore) (Parser parseAfter) =
Parser <| \state ->
List.concatMap parseAfter (parseBefore state)
infixr 7 </>
{-| Transform a path parser.
type alias Comment = { author : String, id : Int }
rawComment : Parser (String -> Int -> a) a
rawComment =
s "user" </> string </> s "comments" </> int
comment : Parser (Comment -> a) a
comment =
map Comment rawComment
parsePath comment location
-- /user/bob/comments/42 ==> Just { author = "bob", id = 42 }
-- /user/tom/comments/35 ==> Just { author = "tom", id = 35 }
-- /user/sam/ ==> Nothing
-}
map : a -> Parser a b -> Parser (b -> c) c
map subValue (Parser parse) =
Parser <| \{ visited, unvisited, params, value } ->
List.map (mapHelp value) <| parse <|
{ visited = visited
, unvisited = unvisited
, params = params
, value = subValue
}
mapHelp : (a -> b) -> State a -> State b
mapHelp func {visited, unvisited, params, value} =
{ visited = visited
, unvisited = unvisited
, params = params
, value = func value
}
{-| Try a bunch of different path parsers.
type Route
= Search String
| Blog Int
| User String
| Comment String Int
route : Parser (Route -> a) a
route =
oneOf
[ map Search (s "search" </> string)
, map Blog (s "blog" </> int)
, map User (s "user" </> string)
, map Comment (s "user" </> string </> "comments" </> int)
]
parsePath route location
-- /search/cats ==> Just (Search "cats")
-- /search/ ==> Nothing
-- /blog/42 ==> Just (Blog 42)
-- /blog/cats ==> Nothing
-- /user/sam/ ==> Just (User "sam")
-- /user/bob/comments/42 ==> Just (Comment "bob" 42)
-- /user/tom/comments/35 ==> Just (Comment "tom" 35)
-- /user/ ==> Nothing
-}
oneOf : List (Parser a b) -> Parser a b
oneOf parsers =
Parser <| \state ->
List.concatMap (\(Parser parser) -> parser state) parsers
{-| A parser that does not consume any path segments.
type BlogRoute = Overview | Post Int
blogRoute : Parser (BlogRoute -> a) a
blogRoute =
oneOf
[ map Overview top
, map Post (s "post" </> int)
]
parsePath (s "blog" </> blogRoute) location
-- /blog/ ==> Just Overview
-- /blog/post/42 ==> Just (Post 42)
-}
top : Parser a a
top =
Parser <| \state -> [state]
-- QUERY PARAMETERS
{-| Turn query parameters like `?name=tom&age=42` into nice Elm data.
-}
type QueryParser a b =
QueryParser (State a -> List (State b))
{-| Parse some query parameters.
type Route = BlogList (Maybe String) | BlogPost Int
route : Parser (Route -> a) a
route =
oneOf
[ map BlogList (s "blog" <?> stringParam "search")
, map BlogPost (s "blog" </> int)
]
parsePath route location
-- /blog/ ==> Just (BlogList Nothing)
-- /blog/?search=cats ==> Just (BlogList (Just "cats"))
-- /blog/42 ==> Just (BlogPost 42)
-}
(<?>) : Parser a b -> QueryParser b c -> Parser a c
(<?>) (Parser parser) (QueryParser queryParser) =
Parser <| \state ->
List.concatMap queryParser (parser state)
infixl 8 <?>
{-| Parse a query parameter as a `String`.
parsePath (s "blog" <?> stringParam "search") location
-- /blog/ ==> Just (Overview Nothing)
-- /blog/?search=cats ==> Just (Overview (Just "cats"))
-}
stringParam : String -> QueryParser (Maybe String -> a) a
stringParam name =
customParam name identity
{-| Parse a query parameter as an `Int`. Maybe you want to show paginated
search results. You could have a `start` query parameter to say which result
should appear first.
parsePath (s "results" <?> intParam "start") location
-- /results ==> Just Nothing
-- /results?start=10 ==> Just (Just 10)
-}
intParam : String -> QueryParser (Maybe Int -> a) a
intParam name =
customParam name intParamHelp
intParamHelp : Maybe String -> Maybe Int
intParamHelp maybeValue =
case maybeValue of
Nothing ->
Nothing
Just value ->
Result.toMaybe (String.toInt value)
{-| Create a custom query parser. You could create parsers like these:
jsonParam : String -> Decoder a -> QueryParser (Maybe a -> b) b
enumParam : String -> Dict String a -> QueryParser (Maybe a -> b) b
It may be worthwhile to have these in this library directly. If you need
either one in practice, please open an issue [here][] describing your exact
scenario. We can use that data to decide if they should be added.
[here]: https://github.com/evancz/url-parser/issues
-}
customParam : String -> (Maybe String -> a) -> QueryParser (a -> b) b
customParam key func =
QueryParser <| \{ visited, unvisited, params, value } ->
[ State visited unvisited params (value (func (Dict.get key params))) ]
-- RUN A PARSER
{-| Parse based on `location.pathname` and `location.search`. This parser
ignores the hash entirely.
-}
parsePath : Parser (a -> a) a -> Navigation.Location -> Maybe a
parsePath parser location =
parse parser location.pathname (parseParams location.search)
{-| Parse based on `location.hash` and `location.search`. This parser
ignores the normal path entirely.
-}
parseHash : Parser (a -> a) a -> Navigation.Location -> Maybe a
parseHash parser location =
parse parser (String.dropLeft 1 location.hash) (parseParams location.search)
-- PARSER HELPERS
parse : Parser (a -> a) a -> String -> Dict String String -> Maybe a
parse (Parser parser) url params =
parseHelp <| parser <|
{ visited = []
, unvisited = splitUrl url
, params = params
, value = identity
}
parseHelp : List (State a) -> Maybe a
parseHelp states =
case states of
[] ->
Nothing
state :: rest ->
case state.unvisited of
[] ->
Just state.value
[""] ->
Just state.value
_ ->
parseHelp rest
splitUrl : String -> List String
splitUrl url =
case String.split "/" url of
"" :: segments ->
segments
segments ->
segments
parseParams : String -> Dict String String
parseParams queryString =
queryString
|> String.dropLeft 1
|> String.split "&"
|> List.filterMap toKeyValuePair
|> Dict.fromList
toKeyValuePair : String -> Maybe (String, String)
toKeyValuePair segment =
case String.split "=" segment of
[key, value] ->
Maybe.map2 (,) (Http.decodeUri key) (Http.decodeUri value)
_ ->
Nothing