elm-pages 3.0.0-beta.1 → 3.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/codegen/elm-pages-codegen.js +803 -284
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15368 -13272
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/dead-code-review/elm.json +6 -5
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +141 -17
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +218 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14574 -12631
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/review/elm.json +6 -6
- package/generator/src/SharedTemplate.elm +1 -1
- package/generator/src/build.js +81 -51
- package/generator/src/cli.js +120 -42
- package/generator/src/codegen.js +11 -10
- package/generator/src/compatibility-key.js +1 -0
- package/generator/src/config.js +41 -0
- package/generator/src/dev-server.js +36 -56
- package/generator/src/elm-codegen.js +3 -0
- package/generator/src/generate-template-module-connector.js +0 -28
- package/generator/src/pre-render-html.js +31 -17
- package/generator/src/render-worker.js +1 -1
- package/generator/src/render.js +224 -37
- package/generator/src/request-cache.js +1 -0
- package/generator/src/rewrite-elm-json.js +3 -3
- package/generator/src/seo-renderer.js +11 -4
- package/generator/src/vite-utils.js +78 -0
- package/generator/template/app/Api.elm +1 -1
- package/generator/template/app/Site.elm +6 -1
- package/package.json +12 -13
- package/src/ApiRoute.elm +146 -11
- package/src/DataSource/Env.elm +27 -3
- package/src/DataSource/File.elm +1 -1
- package/src/DataSource/Internal/Request.elm +0 -5
- package/src/DataSource.elm +50 -53
- package/src/Form/Field.elm +1 -1
- package/src/Form.elm +33 -33
- package/src/Head/Seo.elm +16 -27
- package/src/Head.elm +237 -7
- package/src/HtmlPrinter.elm +7 -3
- package/src/MultiDict.elm +49 -0
- package/src/Pages/Generate.elm +548 -103
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/NotFoundReason.elm +3 -2
- package/src/Pages/Internal/Platform/Cli.elm +91 -27
- package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +455 -0
- package/src/Pages/Internal/Platform.elm +34 -27
- package/src/Pages/Manifest.elm +24 -0
- package/src/Pages/ProgramConfig.elm +6 -3
- package/src/Pages/Script.elm +100 -0
- package/src/PairingHeap.elm +137 -0
- package/src/Parser/Extra/String.elm +33 -0
- package/src/Parser/Extra.elm +69 -0
- package/src/ProgramTest/ComplexQuery.elm +360 -0
- package/src/ProgramTest/EffectSimulation.elm +122 -0
- package/src/ProgramTest/Failure.elm +367 -0
- package/src/ProgramTest/HtmlHighlighter.elm +116 -0
- package/src/ProgramTest/HtmlParserHacks.elm +58 -0
- package/src/ProgramTest/HtmlRenderer.elm +73 -0
- package/src/ProgramTest/Program.elm +30 -0
- package/src/ProgramTest/StringLines.elm +26 -0
- package/src/ProgramTest/TestHtmlHacks.elm +132 -0
- package/src/ProgramTest/TestHtmlParser.elm +201 -0
- package/src/ProgramTest.elm +2339 -0
- package/src/Query/Extra.elm +55 -0
- package/src/Result/Extra.elm +21 -0
- package/src/Server/Request.elm +2 -2
- package/src/Server/Session.elm +149 -83
- package/src/Server/SetCookie.elm +89 -31
- package/src/SimulatedEffect/Cmd.elm +69 -0
- package/src/SimulatedEffect/Http.elm +330 -0
- package/src/SimulatedEffect/Navigation.elm +69 -0
- package/src/SimulatedEffect/Ports.elm +62 -0
- package/src/SimulatedEffect/Process.elm +24 -0
- package/src/SimulatedEffect/Sub.elm +48 -0
- package/src/SimulatedEffect/Task.elm +252 -0
- package/src/SimulatedEffect/Time.elm +25 -0
- package/src/SimulatedEffect.elm +42 -0
- package/src/String/Extra.elm +6 -0
- package/src/Test/Http.elm +145 -0
- package/src/TestResult.elm +35 -0
- package/src/TestState.elm +305 -0
- package/src/Url/Extra.elm +100 -0
- package/src/Vendored/Diff.elm +321 -0
- package/src/Vendored/Failure.elm +217 -0
- package/src/Vendored/FormatMonochrome.elm +44 -0
- package/src/Vendored/Highlightable.elm +53 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module Pages.Script exposing
|
|
2
|
+
( Script(..)
|
|
3
|
+
, withCliOptions, withoutCliOptions
|
|
4
|
+
, writeFile
|
|
5
|
+
, log
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
{-|
|
|
9
|
+
|
|
10
|
+
@docs Script
|
|
11
|
+
|
|
12
|
+
@docs withCliOptions, withoutCliOptions
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## File System Utilities
|
|
16
|
+
|
|
17
|
+
@docs writeFile
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Utilities
|
|
21
|
+
|
|
22
|
+
@docs log
|
|
23
|
+
|
|
24
|
+
-}
|
|
25
|
+
|
|
26
|
+
import Cli.OptionsParser as OptionsParser
|
|
27
|
+
import Cli.Program as Program
|
|
28
|
+
import DataSource exposing (DataSource)
|
|
29
|
+
import DataSource.Http
|
|
30
|
+
import DataSource.Internal.Request
|
|
31
|
+
import Html exposing (Html)
|
|
32
|
+
import Json.Decode as Decode
|
|
33
|
+
import Json.Encode as Encode
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
{-| -}
|
|
37
|
+
type Script
|
|
38
|
+
= Generator
|
|
39
|
+
((Maybe { indent : Int, newLines : Bool }
|
|
40
|
+
-> Html Never
|
|
41
|
+
-> String
|
|
42
|
+
)
|
|
43
|
+
-> Program.Config (DataSource ())
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
{-| -}
|
|
48
|
+
writeFile : { path : String, body : String } -> DataSource ()
|
|
49
|
+
writeFile { path, body } =
|
|
50
|
+
DataSource.Internal.Request.request
|
|
51
|
+
{ name = "write-file"
|
|
52
|
+
, body =
|
|
53
|
+
DataSource.Http.jsonBody
|
|
54
|
+
(Encode.object
|
|
55
|
+
[ ( "path", Encode.string path )
|
|
56
|
+
, ( "body", Encode.string body )
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
, expect = DataSource.Http.expectJson (Decode.succeed ())
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
{-| -}
|
|
64
|
+
log : String -> DataSource ()
|
|
65
|
+
log message =
|
|
66
|
+
DataSource.Internal.Request.request
|
|
67
|
+
{ name = "log"
|
|
68
|
+
, body =
|
|
69
|
+
DataSource.Http.jsonBody
|
|
70
|
+
(Encode.object
|
|
71
|
+
[ ( "message", Encode.string message )
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
, expect = DataSource.Http.expectJson (Decode.succeed ())
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
{-| -}
|
|
79
|
+
withoutCliOptions : DataSource () -> Script
|
|
80
|
+
withoutCliOptions execute =
|
|
81
|
+
Generator
|
|
82
|
+
(\_ ->
|
|
83
|
+
Program.config
|
|
84
|
+
|> Program.add
|
|
85
|
+
(OptionsParser.build ())
|
|
86
|
+
|> Program.mapConfig
|
|
87
|
+
(\() ->
|
|
88
|
+
execute
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
{-| -}
|
|
94
|
+
withCliOptions : Program.Config cliOptions -> (cliOptions -> DataSource ()) -> Script
|
|
95
|
+
withCliOptions config execute =
|
|
96
|
+
Generator
|
|
97
|
+
(\_ ->
|
|
98
|
+
config
|
|
99
|
+
|> Program.mapConfig execute
|
|
100
|
+
)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module PairingHeap exposing
|
|
2
|
+
( PairingHeap, empty
|
|
3
|
+
, insert, merge, findMin, deleteMin
|
|
4
|
+
, fromList, toSortedList
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
{-| This is a simple pairing heap implementation written in Elm usable as a priority queue. This code is
|
|
8
|
+
based heavily on the pseudocode available at [the Wikipedia page](https://en.wikipedia.org/wiki/Pairing_heap).
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Type and Constructor
|
|
12
|
+
|
|
13
|
+
@docs PairingHeap, empty
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Operations
|
|
17
|
+
|
|
18
|
+
@docs insert, merge, findMin, deleteMin
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Convenience functions
|
|
22
|
+
|
|
23
|
+
@docs fromList, toSortedList
|
|
24
|
+
|
|
25
|
+
-}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
{-| A `PairingHeap` has comparable keys and values of an arbitrary type.
|
|
29
|
+
-}
|
|
30
|
+
type PairingHeap comparable a
|
|
31
|
+
= Empty
|
|
32
|
+
| Heap comparable a (List (PairingHeap comparable a))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
{-| Create an empty PairingHeap.
|
|
36
|
+
-}
|
|
37
|
+
empty : PairingHeap comparable a
|
|
38
|
+
empty =
|
|
39
|
+
Empty
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
{-| Find the minimum value in a heap returning Nothing if the heap is empty.
|
|
43
|
+
Complexity: O(1)
|
|
44
|
+
|
|
45
|
+
findMin (fromList [ ( 10, () ), ( 3, () ), ( 8, () ) ]) == Just 3
|
|
46
|
+
|
|
47
|
+
-}
|
|
48
|
+
findMin : PairingHeap comparable a -> Maybe ( comparable, a )
|
|
49
|
+
findMin x =
|
|
50
|
+
case x of
|
|
51
|
+
Empty ->
|
|
52
|
+
Nothing
|
|
53
|
+
|
|
54
|
+
Heap k v _ ->
|
|
55
|
+
Just ( k, v )
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
{-| Merges two `PairingHeap`s together into one new heap containing all of the key-value pairs from both inputs.
|
|
59
|
+
Complexity: O(1)
|
|
60
|
+
-}
|
|
61
|
+
merge : PairingHeap comparable a -> PairingHeap comparable a -> PairingHeap comparable a
|
|
62
|
+
merge heap1 heap2 =
|
|
63
|
+
case ( heap1, heap2 ) of
|
|
64
|
+
( Empty, _ ) ->
|
|
65
|
+
heap2
|
|
66
|
+
|
|
67
|
+
( _, Empty ) ->
|
|
68
|
+
heap1
|
|
69
|
+
|
|
70
|
+
( Heap k1 v1 hs1, Heap k2 v2 hs2 ) ->
|
|
71
|
+
if k1 < k2 then
|
|
72
|
+
Heap k1 v1 (heap2 :: hs1)
|
|
73
|
+
|
|
74
|
+
else
|
|
75
|
+
Heap k2 v2 (heap1 :: hs2)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
{-| Inserts a new element into a `PairingHeap`.
|
|
79
|
+
Complexity: O(1)
|
|
80
|
+
-}
|
|
81
|
+
insert : comparable -> a -> PairingHeap comparable a -> PairingHeap comparable a
|
|
82
|
+
insert k v heap =
|
|
83
|
+
merge (Heap k v []) heap
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
{-| Removes the minimum element from a `PairingHeap` returning a new heap without that element.
|
|
87
|
+
This will return an empty heap if given an empty heap as input.
|
|
88
|
+
Complexity: O(log n)
|
|
89
|
+
-}
|
|
90
|
+
deleteMin : PairingHeap comparable a -> PairingHeap comparable a
|
|
91
|
+
deleteMin heap =
|
|
92
|
+
case heap of
|
|
93
|
+
Empty ->
|
|
94
|
+
Empty
|
|
95
|
+
|
|
96
|
+
Heap k v heaps ->
|
|
97
|
+
mergePairs heaps
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
{-| This is an internal function used by deleteMin.
|
|
101
|
+
-}
|
|
102
|
+
mergePairs : List (PairingHeap comparable a) -> PairingHeap comparable a
|
|
103
|
+
mergePairs heaps =
|
|
104
|
+
case heaps of
|
|
105
|
+
[] ->
|
|
106
|
+
Empty
|
|
107
|
+
|
|
108
|
+
x :: [] ->
|
|
109
|
+
x
|
|
110
|
+
|
|
111
|
+
x :: (y :: xs) ->
|
|
112
|
+
merge (merge x y) (mergePairs xs)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
-- Extra convenience functions
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
{-| This function turns a list of key-value pairs into a `PairingHeap`.
|
|
120
|
+
Complexity: O(n)
|
|
121
|
+
-}
|
|
122
|
+
fromList : List ( comparable, a ) -> PairingHeap comparable a
|
|
123
|
+
fromList =
|
|
124
|
+
List.foldl (\( k, v ) -> insert k v) empty
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
{-| This function turns a `PairingHeap` into a sorted list of key-value pairs.
|
|
128
|
+
Complexity: O(n log n)
|
|
129
|
+
-}
|
|
130
|
+
toSortedList : PairingHeap comparable a -> List ( comparable, a )
|
|
131
|
+
toSortedList heap =
|
|
132
|
+
case heap of
|
|
133
|
+
Empty ->
|
|
134
|
+
[]
|
|
135
|
+
|
|
136
|
+
Heap k v _ ->
|
|
137
|
+
( k, v ) :: toSortedList (deleteMin heap)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Parser.Extra.String exposing (string)
|
|
2
|
+
|
|
3
|
+
import Parser exposing (..)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
string : Parser String
|
|
7
|
+
string =
|
|
8
|
+
succeed identity
|
|
9
|
+
|. token "\""
|
|
10
|
+
|= loop [] stringHelp
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
stringHelp : List String -> Parser (Step (List String) String)
|
|
14
|
+
stringHelp revChunks =
|
|
15
|
+
oneOf
|
|
16
|
+
[ succeed (\chunk -> Loop (chunk :: revChunks))
|
|
17
|
+
|. token "\\"
|
|
18
|
+
|= oneOf
|
|
19
|
+
[ map (\_ -> "\n") (token "n")
|
|
20
|
+
, map (\_ -> "\t") (token "t")
|
|
21
|
+
, map (\_ -> "\u{000D}") (token "r")
|
|
22
|
+
]
|
|
23
|
+
, token "\""
|
|
24
|
+
|> map (\_ -> Done (String.join "" (List.reverse revChunks)))
|
|
25
|
+
, chompWhile isUninteresting
|
|
26
|
+
|> getChompedString
|
|
27
|
+
|> map (\chunk -> Loop (chunk :: revChunks))
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
isUninteresting : Char -> Bool
|
|
32
|
+
isUninteresting char =
|
|
33
|
+
char /= '\\' && char /= '"'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Parser.Extra exposing (deadEndsToString)
|
|
2
|
+
|
|
3
|
+
{-| [No implementation for deadEndsToString · Issue #9 · elm/parser](https://github.com/elm/parser/issues/9)
|
|
4
|
+
-}
|
|
5
|
+
|
|
6
|
+
import Parser exposing (DeadEnd, Problem(..))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
deadEndsToString : List DeadEnd -> String
|
|
10
|
+
deadEndsToString deadEnds =
|
|
11
|
+
String.join "\n" (List.map deadEndToString deadEnds)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
deadEndToString : DeadEnd -> String
|
|
15
|
+
deadEndToString deadEnd =
|
|
16
|
+
problemToString deadEnd.problem
|
|
17
|
+
++ " at "
|
|
18
|
+
++ deadEndToRowColString deadEnd
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
problemToString : Problem -> String
|
|
22
|
+
problemToString prob =
|
|
23
|
+
case prob of
|
|
24
|
+
Expecting s ->
|
|
25
|
+
"Expecting " ++ s
|
|
26
|
+
|
|
27
|
+
ExpectingInt ->
|
|
28
|
+
"Expecting Int"
|
|
29
|
+
|
|
30
|
+
ExpectingHex ->
|
|
31
|
+
"Expecting Hex"
|
|
32
|
+
|
|
33
|
+
ExpectingOctal ->
|
|
34
|
+
"Expecting Octal"
|
|
35
|
+
|
|
36
|
+
ExpectingBinary ->
|
|
37
|
+
"Expecting Binary"
|
|
38
|
+
|
|
39
|
+
ExpectingFloat ->
|
|
40
|
+
"Expecting Float"
|
|
41
|
+
|
|
42
|
+
ExpectingNumber ->
|
|
43
|
+
"Expecting Number"
|
|
44
|
+
|
|
45
|
+
ExpectingVariable ->
|
|
46
|
+
"Expecting Variable"
|
|
47
|
+
|
|
48
|
+
ExpectingSymbol s ->
|
|
49
|
+
"Expecting Symbol " ++ s
|
|
50
|
+
|
|
51
|
+
ExpectingKeyword s ->
|
|
52
|
+
"Expecting Keyword " ++ s
|
|
53
|
+
|
|
54
|
+
ExpectingEnd ->
|
|
55
|
+
"Expecting End"
|
|
56
|
+
|
|
57
|
+
UnexpectedChar ->
|
|
58
|
+
"Unexpected Char"
|
|
59
|
+
|
|
60
|
+
Problem s ->
|
|
61
|
+
"Problem: " ++ s
|
|
62
|
+
|
|
63
|
+
BadRepeat ->
|
|
64
|
+
"Bad Repeat"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
deadEndToRowColString : DeadEnd -> String
|
|
68
|
+
deadEndToRowColString deadEnd =
|
|
69
|
+
"row " ++ String.fromInt deadEnd.row ++ ", " ++ "col " ++ String.fromInt deadEnd.col
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
module ProgramTest.ComplexQuery exposing (ComplexQuery, Failure(..), FailureContext, FailureContext1(..), Highlight, Priority, check, exactlyOneOf, find, findButNot, run, simulate, succeed)
|
|
2
|
+
|
|
3
|
+
import Json.Encode as Json
|
|
4
|
+
import ProgramTest.TestHtmlHacks as TestHtmlHacks
|
|
5
|
+
import ProgramTest.TestHtmlParser as TestHtmlParser
|
|
6
|
+
import Result.Extra
|
|
7
|
+
import Set exposing (Set)
|
|
8
|
+
import Test.Html.Event
|
|
9
|
+
import Test.Html.Query as Query
|
|
10
|
+
import Test.Html.Selector as Selector exposing (Selector)
|
|
11
|
+
import Test.Runner
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
type ComplexQuery a
|
|
15
|
+
= QueryResult State Highlight (List FailureContext1) (Result Failure a)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
succeed : a -> ComplexQuery a
|
|
19
|
+
succeed a =
|
|
20
|
+
QueryResult initState Set.empty [] (Ok a)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
type alias Priority =
|
|
24
|
+
Int
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
type alias State =
|
|
28
|
+
{ priority : Priority
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
initState : State
|
|
33
|
+
initState =
|
|
34
|
+
{ priority = 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
type Failure
|
|
39
|
+
= QueryFailed (List (Result String String))
|
|
40
|
+
| SimulateFailed String
|
|
41
|
+
| NoMatches String (List ( String, Priority, ( List FailureContext1, Failure ) ))
|
|
42
|
+
| TooManyMatches String (List ( String, Priority, List FailureContext1 ))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
type alias FailureContext =
|
|
46
|
+
List FailureContext1
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
type FailureContext1
|
|
50
|
+
= FindSucceeded (Maybe String) (() -> List String)
|
|
51
|
+
| CheckSucceeded String (List FailureContext1)
|
|
52
|
+
| Description (Result String String)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
type alias Highlight =
|
|
56
|
+
Set String
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
run : ComplexQuery a -> ( Highlight, Result ( List FailureContext1, Failure ) a )
|
|
60
|
+
run (QueryResult _ highlight context result) =
|
|
61
|
+
( highlight
|
|
62
|
+
, case result of
|
|
63
|
+
Ok a ->
|
|
64
|
+
Ok a
|
|
65
|
+
|
|
66
|
+
Err error ->
|
|
67
|
+
Err ( List.reverse context, error )
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
find : Maybe String -> List String -> List Selector -> ComplexQuery (Query.Single msg) -> ComplexQuery (Query.Single msg)
|
|
72
|
+
find description highlight selectors prev =
|
|
73
|
+
case prev of
|
|
74
|
+
QueryResult _ _ _ (Err _) ->
|
|
75
|
+
prev
|
|
76
|
+
|
|
77
|
+
QueryResult state prevHighlight prevContext (Ok source) ->
|
|
78
|
+
case Test.Runner.getFailureReason (Query.has [ Selector.all selectors ] source) of
|
|
79
|
+
Just _ ->
|
|
80
|
+
let
|
|
81
|
+
error =
|
|
82
|
+
firstErrorOf source
|
|
83
|
+
[ selectors
|
|
84
|
+
, [ Selector.all selectors ]
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
context =
|
|
88
|
+
case description of
|
|
89
|
+
Nothing ->
|
|
90
|
+
[]
|
|
91
|
+
|
|
92
|
+
Just desc ->
|
|
93
|
+
[ Description (Err desc) ]
|
|
94
|
+
in
|
|
95
|
+
QueryResult
|
|
96
|
+
{ state
|
|
97
|
+
| priority = state.priority + countSuccesses error
|
|
98
|
+
}
|
|
99
|
+
(Set.union (Set.fromList highlight) prevHighlight)
|
|
100
|
+
(context ++ prevContext)
|
|
101
|
+
(Err (QueryFailed error))
|
|
102
|
+
|
|
103
|
+
Nothing ->
|
|
104
|
+
QueryResult
|
|
105
|
+
{ state
|
|
106
|
+
| priority = state.priority + List.length selectors
|
|
107
|
+
}
|
|
108
|
+
(Set.union (Set.fromList highlight) prevHighlight)
|
|
109
|
+
(FindSucceeded description (\() -> TestHtmlHacks.getPassingSelectors selectors source) :: prevContext)
|
|
110
|
+
(Ok (Query.find selectors source))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
exactlyOneOf : String -> List ( String, ComplexQuery a -> ComplexQuery b ) -> ComplexQuery a -> ComplexQuery b
|
|
114
|
+
exactlyOneOf description options prev =
|
|
115
|
+
case prev of
|
|
116
|
+
QueryResult state prevHighlight prevContext (Err err) ->
|
|
117
|
+
QueryResult state prevHighlight prevContext (Err err)
|
|
118
|
+
|
|
119
|
+
QueryResult state prevHighlight prevContext (Ok _) ->
|
|
120
|
+
let
|
|
121
|
+
results : List ( String, ComplexQuery b )
|
|
122
|
+
results =
|
|
123
|
+
List.map (Tuple.mapSecond (\option -> option prev)) options
|
|
124
|
+
|
|
125
|
+
successes : List ( String, ComplexQuery b )
|
|
126
|
+
successes =
|
|
127
|
+
List.filter (isSuccess << Tuple.second) results
|
|
128
|
+
|
|
129
|
+
isSuccess res =
|
|
130
|
+
case res of
|
|
131
|
+
QueryResult _ _ _ (Err _) ->
|
|
132
|
+
False
|
|
133
|
+
|
|
134
|
+
QueryResult _ _ _ (Ok _) ->
|
|
135
|
+
True
|
|
136
|
+
|
|
137
|
+
collectHighlight (QueryResult _ highlight _ _) =
|
|
138
|
+
highlight
|
|
139
|
+
|
|
140
|
+
highlights =
|
|
141
|
+
List.map (collectHighlight << Tuple.second) results
|
|
142
|
+
|> List.foldl Set.union Set.empty
|
|
143
|
+
|
|
144
|
+
collectError ( desc, QueryResult newState _ context result ) =
|
|
145
|
+
case result of
|
|
146
|
+
Ok _ ->
|
|
147
|
+
Nothing
|
|
148
|
+
|
|
149
|
+
Err x ->
|
|
150
|
+
Just
|
|
151
|
+
( desc
|
|
152
|
+
, newState.priority
|
|
153
|
+
, ( List.reverse context, x )
|
|
154
|
+
)
|
|
155
|
+
in
|
|
156
|
+
case successes of
|
|
157
|
+
[ ( _, one ) ] ->
|
|
158
|
+
one
|
|
159
|
+
|
|
160
|
+
[] ->
|
|
161
|
+
let
|
|
162
|
+
failures =
|
|
163
|
+
List.filterMap collectError results
|
|
164
|
+
in
|
|
165
|
+
QueryResult
|
|
166
|
+
state
|
|
167
|
+
(Set.union highlights prevHighlight)
|
|
168
|
+
prevContext
|
|
169
|
+
(Err (NoMatches description failures))
|
|
170
|
+
|
|
171
|
+
many ->
|
|
172
|
+
let
|
|
173
|
+
matches =
|
|
174
|
+
List.map
|
|
175
|
+
(\( desc, QueryResult newState _ context _ ) ->
|
|
176
|
+
( desc, newState.priority, context )
|
|
177
|
+
)
|
|
178
|
+
many
|
|
179
|
+
in
|
|
180
|
+
QueryResult
|
|
181
|
+
state
|
|
182
|
+
(Set.union highlights prevHighlight)
|
|
183
|
+
prevContext
|
|
184
|
+
(Err (TooManyMatches description matches))
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
{-|
|
|
188
|
+
|
|
189
|
+
- `good`: the primary selector that must match
|
|
190
|
+
- `bads`: a list of selectors that must NOT match
|
|
191
|
+
- `onError`: the selector to use to produce an error message if any of the checks fail
|
|
192
|
+
|
|
193
|
+
-}
|
|
194
|
+
findButNot :
|
|
195
|
+
Maybe String
|
|
196
|
+
-> List String
|
|
197
|
+
->
|
|
198
|
+
{ good : List Selector
|
|
199
|
+
, bads : List (List Selector)
|
|
200
|
+
, onError : List Selector
|
|
201
|
+
}
|
|
202
|
+
-> ComplexQuery (Query.Single msg)
|
|
203
|
+
-> ComplexQuery (Query.Single msg)
|
|
204
|
+
findButNot description highlight { good, bads, onError } prev =
|
|
205
|
+
case prev of
|
|
206
|
+
QueryResult _ _ _ (Err _) ->
|
|
207
|
+
prev
|
|
208
|
+
|
|
209
|
+
QueryResult state prevHighlight prevContext (Ok source) ->
|
|
210
|
+
-- This is tricky because Test.Html doesn't provide a way to search for an attribute being *not* present.
|
|
211
|
+
-- So we have to check if a selector we don't want *is* present, and manually force a failure if it is.
|
|
212
|
+
let
|
|
213
|
+
addDescription =
|
|
214
|
+
case description of
|
|
215
|
+
Nothing ->
|
|
216
|
+
[]
|
|
217
|
+
|
|
218
|
+
Just desc ->
|
|
219
|
+
[ Description (Err desc) ]
|
|
220
|
+
|
|
221
|
+
checkBads : Priority -> List (List Selector) -> Query.Single msg -> ComplexQuery (Query.Single msg)
|
|
222
|
+
checkBads extraPriority bads_ found =
|
|
223
|
+
case bads_ of
|
|
224
|
+
[] ->
|
|
225
|
+
QueryResult
|
|
226
|
+
{ state | priority = state.priority + extraPriority + 1 }
|
|
227
|
+
(Set.union (Set.fromList highlight) prevHighlight)
|
|
228
|
+
-- TODO: add the not bads to the context (or alternatively, add the "onErrors", but convert them all to successes)
|
|
229
|
+
(FindSucceeded description (\() -> TestHtmlHacks.getPassingSelectors good source) :: prevContext)
|
|
230
|
+
(Ok found)
|
|
231
|
+
|
|
232
|
+
nextBad :: rest ->
|
|
233
|
+
let
|
|
234
|
+
isBad =
|
|
235
|
+
Query.has [ Selector.all nextBad ] source
|
|
236
|
+
in
|
|
237
|
+
case Test.Runner.getFailureReason isBad of
|
|
238
|
+
Nothing ->
|
|
239
|
+
-- the element matches the bad selectors; produce a Query using the onError selectors that will fail that will show a reasonable failure message
|
|
240
|
+
let
|
|
241
|
+
error =
|
|
242
|
+
firstErrorOf source
|
|
243
|
+
[ good
|
|
244
|
+
, [ Selector.all good ]
|
|
245
|
+
, onError
|
|
246
|
+
, [ Selector.all onError ]
|
|
247
|
+
]
|
|
248
|
+
in
|
|
249
|
+
QueryResult
|
|
250
|
+
{ state | priority = state.priority + extraPriority + countSuccesses error }
|
|
251
|
+
(Set.union (Set.fromList highlight) prevHighlight)
|
|
252
|
+
(addDescription ++ prevContext)
|
|
253
|
+
(Err (QueryFailed error))
|
|
254
|
+
|
|
255
|
+
Just _ ->
|
|
256
|
+
-- the element we found is not bad; continue on to the next check
|
|
257
|
+
checkBads (extraPriority + List.length nextBad) rest found
|
|
258
|
+
|
|
259
|
+
isGood =
|
|
260
|
+
Query.has [ Selector.all good ] source
|
|
261
|
+
in
|
|
262
|
+
case Test.Runner.getFailureReason isGood of
|
|
263
|
+
Just _ ->
|
|
264
|
+
-- Couldn't find it, so report the best error message we can
|
|
265
|
+
let
|
|
266
|
+
error =
|
|
267
|
+
firstErrorOf source
|
|
268
|
+
[ good
|
|
269
|
+
, [ Selector.all good ]
|
|
270
|
+
]
|
|
271
|
+
in
|
|
272
|
+
QueryResult
|
|
273
|
+
{ state | priority = state.priority + countSuccesses error }
|
|
274
|
+
(Set.union (Set.fromList highlight) prevHighlight)
|
|
275
|
+
prevContext
|
|
276
|
+
(Err (QueryFailed error))
|
|
277
|
+
|
|
278
|
+
Nothing ->
|
|
279
|
+
Query.find good source
|
|
280
|
+
|> checkBads (List.length good) bads
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
simulate : ( String, Json.Value ) -> ComplexQuery (Query.Single msg) -> ComplexQuery msg
|
|
284
|
+
simulate event prev =
|
|
285
|
+
case prev of
|
|
286
|
+
QueryResult state prevHighlight prevContext (Err err) ->
|
|
287
|
+
QueryResult state prevHighlight prevContext (Err err)
|
|
288
|
+
|
|
289
|
+
QueryResult state prevHighlight prevContext (Ok source) ->
|
|
290
|
+
case
|
|
291
|
+
source
|
|
292
|
+
|> Test.Html.Event.simulate event
|
|
293
|
+
|> Test.Html.Event.toResult
|
|
294
|
+
of
|
|
295
|
+
Err message ->
|
|
296
|
+
QueryResult
|
|
297
|
+
state
|
|
298
|
+
prevHighlight
|
|
299
|
+
(Description (Err ("simulate " ++ Tuple.first event)) :: prevContext)
|
|
300
|
+
(Err (SimulateFailed (TestHtmlHacks.parseSimulateFailure message)))
|
|
301
|
+
|
|
302
|
+
Ok msg ->
|
|
303
|
+
QueryResult state prevHighlight prevContext (Ok msg)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
{-| Ensure that the given query succeeds, but then ignore its result.
|
|
307
|
+
-}
|
|
308
|
+
check : String -> (ComplexQuery a -> ComplexQuery ignored) -> ComplexQuery a -> ComplexQuery a
|
|
309
|
+
check description checkQuery prev =
|
|
310
|
+
case prev of
|
|
311
|
+
QueryResult _ _ _ (Err _) ->
|
|
312
|
+
prev
|
|
313
|
+
|
|
314
|
+
QueryResult state prevHighlight prevContext (Ok source) ->
|
|
315
|
+
let
|
|
316
|
+
(QueryResult checkedState highlight checkContext checkResult) =
|
|
317
|
+
checkQuery (QueryResult state prevHighlight [] (Ok source))
|
|
318
|
+
in
|
|
319
|
+
case checkResult of
|
|
320
|
+
Err failure ->
|
|
321
|
+
QueryResult
|
|
322
|
+
checkedState
|
|
323
|
+
(Set.union highlight prevHighlight)
|
|
324
|
+
(Description (Err description) :: checkContext ++ prevContext)
|
|
325
|
+
(Err failure)
|
|
326
|
+
|
|
327
|
+
Ok _ ->
|
|
328
|
+
QueryResult
|
|
329
|
+
{ state | priority = checkedState.priority }
|
|
330
|
+
(Set.union highlight prevHighlight)
|
|
331
|
+
(CheckSucceeded description checkContext :: prevContext)
|
|
332
|
+
(Ok source)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
firstErrorOf : Query.Single msg -> List (List Selector) -> List (Result String String)
|
|
336
|
+
firstErrorOf source choices =
|
|
337
|
+
case choices of
|
|
338
|
+
[] ->
|
|
339
|
+
[ Err "PLEASE REPORT THIS AT <https://github.com/avh4/elm-program-test/issues>: firstErrorOf: asked to report an error but none of the choices failed" ]
|
|
340
|
+
|
|
341
|
+
next :: rest ->
|
|
342
|
+
case Test.Runner.getFailureReason (Query.has next source) of
|
|
343
|
+
Just reason ->
|
|
344
|
+
case TestHtmlHacks.parseFailureReportWithoutHtml reason.description of
|
|
345
|
+
Ok (TestHtmlParser.QueryFailure _ _ (TestHtmlParser.Has _ results)) ->
|
|
346
|
+
results
|
|
347
|
+
|
|
348
|
+
Ok (TestHtmlParser.EventFailure name _) ->
|
|
349
|
+
[ Err ("PLEASE REPORT THIS AT <https://github.com/avh4/elm-program-test/issues>: firstErrorOf: got unexpected EventFailure \"" ++ name ++ "\"") ]
|
|
350
|
+
|
|
351
|
+
Err err ->
|
|
352
|
+
[ Err ("PLEASE REPORT THIS AT <https://github.com/avh4/elm-program-test/issues>: firstErrorOf: couldn't parse failure report: " ++ err) ]
|
|
353
|
+
|
|
354
|
+
Nothing ->
|
|
355
|
+
firstErrorOf source rest
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
countSuccesses : List (Result String String) -> Int
|
|
359
|
+
countSuccesses results =
|
|
360
|
+
List.length (List.filter Result.Extra.isOk results)
|