Play

Check-in [1285a94244]
Login
Overview
Comment:PackageLoader now supports reading in all relevant play.json files.
Timelines: family | ancestors | descendants | both | modules
Files: files | file ages | folders
SHA3-256: 1285a94244850513fd51c49d1a9c4527287294221268f091c1d9d25d84907a39
User & Date: robin.hansen on 2021-02-19 16:29:15
Other Links: branch diff | manifest | tags
Context
2021-02-21
10:51
Implement function to check compatibility between semver versions. check-in: eb5381534d user: robin.hansen tags: modules
2021-02-19
16:29
PackageLoader now supports reading in all relevant play.json files. check-in: 1285a94244 user: robin.hansen tags: modules
2021-02-15
09:38
Refactor code to improve readability. Also validate key entries of dependencies field in play.json. check-in: b5d7173dee user: robin.hansen tags: modules
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/Data/PackageName.elm from [f7a2e868d7] to [83dc1a13a9].

1
2
3
4

5
6
7
8
9
10
11
..
30
31
32
33
34
35
36





module Play.Data.PackageName exposing
    ( PackageName
    , fromString
    , invalidPart

    )


type PackageName
    = PackageName String String


................................................................................
            True

        Just ( first, rest ) ->
            not
                (Char.isLower first
                    && String.all (\c -> Char.isLower c || Char.isDigit c || c == '_') rest
                )









>







 







>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
..
31
32
33
34
35
36
37
38
39
40
41
42
module Play.Data.PackageName exposing
    ( PackageName
    , fromString
    , invalidPart
    , toString
    )


type PackageName
    = PackageName String String


................................................................................
            True

        Just ( first, rest ) ->
            not
                (Char.isLower first
                    && String.all (\c -> Char.isLower c || Char.isDigit c || c == '_') rest
                )


toString : PackageName -> String
toString (PackageName group name) =
    group ++ "/" ++ name

Modified src/Play/Data/PackagePath.elm from [88408bbd3f] to [b58e74fd1c].

1
2
3

4
5
6
7
8
9
10
..
29
30
31
32
33
34
35










module Play.Data.PackagePath exposing
    ( PackagePath(..)
    , fromString

    )


type PackagePath
    = Directory String
    | AllDirectoriesInDirectory String

................................................................................
            else if String.endsWith "/" str then
                1

            else
                0
    in
    ctor <| String.dropRight charsToDrop str













>







 







>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
..
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
module Play.Data.PackagePath exposing
    ( PackagePath(..)
    , fromString
    , prefix
    )


type PackagePath
    = Directory String
    | AllDirectoriesInDirectory String

................................................................................
            else if String.endsWith "/" str then
                1

            else
                0
    in
    ctor <| String.dropRight charsToDrop str


prefix : String -> PackagePath -> PackagePath
prefix pathToPrefix packagePath =
    case packagePath of
        Directory dir ->
            Directory <| pathToPrefix ++ "/" ++ dir

        AllDirectoriesInDirectory dir ->
            AllDirectoriesInDirectory <| pathToPrefix ++ "/" ++ dir

Modified src/Play/PackageLoader.elm from [9106e2c582] to [510bc0213d].

1







2


3

4


5
6
7
8
9
10















11
12

13
14











15
16


17
18
19
20





















21
22




















23
24










25
26





















module Play.PackageLoader exposing (init)










import Json.Decode as Json

import Play.Data.PackageMetadata as PackageMetadata




type Problem
    = InvalidPackageMetadata String String

















type alias State =
    ()














type SideEffect
    = NoOp




init : String -> String -> Result Problem ( State, SideEffect )
init jsonFilePath json =





















    case Json.decodeString PackageMetadata.decoder json of
        Ok metadata ->




















            Ok ( (), NoOp )











        Err err ->
            Err <| InvalidPackageMetadata jsonFilePath (Json.errorToString err)





















|
>
>
>
>
>
>
>
|
>
>

>
|
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
>
|

>
>
>
>
>
>
>
>
>
>
>


>
>


<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module Play.PackageLoader exposing
    ( Model
    , Msg(..)
    , Problem
    , SideEffect(..)
    , doneState
    , init
    , update
    )

import Dict exposing (Dict)
import Json.Decode as Json
import List.Extra as List
import Play.Data.PackageMetadata as PackageMetadata exposing (PackageMetadata)
import Play.Data.PackageName as PackageName
import Play.Data.PackagePath as PackagePath exposing (PackagePath)


type Problem
    = InvalidPackageMetadata String String


type Model
    = LoadingMetadata State (List PackagePath)
    | Done State


doneState : Model -> Maybe State
doneState model =
    case model of
        Done state ->
            Just state

        _ ->
            Nothing


type alias State =

    { loadedPackages : Dict String PackageMetadata
    }


emptyState : State
emptyState =
    { loadedPackages = Dict.empty }


type Msg
    = FileContents String String String
    | ResolvedDirectories String (List PackagePath)


type SideEffect
    = NoOp
    | ReadFile String String
    | ResolveDirectories String




init : String -> ( Model, SideEffect )
init projectDirPath =
    ( LoadingMetadata emptyState [ PackagePath.Directory projectDirPath ]
    , ReadFile projectDirPath "play.json"
    )


update : Msg -> Model -> ( Model, SideEffect )
update msg model =
    case model of
        Done _ ->
            ( model, NoOp )

        LoadingMetadata state remainingPaths ->
            loadingMetadataUpdate msg state remainingPaths


loadingMetadataUpdate : Msg -> State -> List PackagePath -> ( Model, SideEffect )
loadingMetadataUpdate msg state remainingPaths =
    case msg of
        FileContents path _ content ->
            case Json.decodeString PackageMetadata.decoder content of
                Ok metadata ->
                    let
                        updatedState =
                            { state
                                | loadedPackages =
                                    Dict.insert
                                        (PackageName.toString metadata.name)
                                        metadata
                                        state.loadedPackages
                            }

                        absolutePackagePaths =
                            List.map (PackagePath.prefix path) metadata.packagePaths

                        pathsToLoad =
                            remainingPaths
                                |> List.remove (PackagePath.Directory path)
                                |> (++) absolutePackagePaths
                    in
                    case pathsToLoad of
                        [] ->
                            ( Done updatedState, NoOp )

                        (PackagePath.Directory nextPathDir) :: _ ->
                            ( LoadingMetadata updatedState pathsToLoad
                            , ReadFile nextPathDir "play.json"
                            )

                        (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                            ( LoadingMetadata updatedState pathsToLoad
                            , ResolveDirectories nextPathDir
                            )

                Err err ->
                    Debug.todo (Json.errorToString err)

        ResolvedDirectories parentDir paths ->
            let
                pathsToLoad =
                    remainingPaths
                        |> List.remove (PackagePath.AllDirectoriesInDirectory parentDir)
                        |> (++) paths
            in
            case pathsToLoad of
                [] ->
                    ( Done state, NoOp )

                (PackagePath.Directory nextPathDir) :: _ ->
                    ( LoadingMetadata state pathsToLoad
                    , ReadFile nextPathDir "play.json"
                    )

                (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                    ( LoadingMetadata state pathsToLoad
                    , ResolveDirectories <| parentDir ++ "/" ++ nextPathDir
                    )

Modified tests/Test/PackageLoader.elm from [a2e078e664] to [6452199eaa].

1
2

3
4

5
6
7
8
9
10
11
12
13
14
15































































16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32









33








module Test.PackageLoader exposing (suite)


import Expect
import Fuzz

import Play.PackageLoader as PackageLoader
import Test exposing (Test, describe, fuzz, test)
import Test.PlayExpect as PlayExpect


suite : Test
suite =
    describe "PackageLoader"
        [ test "Passes the load package metadata step" <|
            \_ ->
                PackageLoader.init "play.json"































































                    """
                    {
                        "name": "robheghan/fnv",
                        "version": "1.0.0",
                        "language-version": "0.2.0",
                        "exposed-modules": [
                            "fnv"
                        ],
                        "dependencies": {
                            "jarvis/template_strings": "1.2.0"
                        },
                        "package-paths": [
                            "lib/*"
                        ]
                    }
                    """
                    |> Expect.ok









        ]










>
|
|
>

|
<







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
module Test.PackageLoader exposing (suite)

import Dict exposing (Dict)
import Expect exposing (Expectation)
import List.Extra as List
import Play.Data.PackagePath as PackagePath
import Play.PackageLoader as PackageLoader
import Test exposing (Test, describe, test)



suite : Test
suite =
    describe "PackageLoader"
        [ test "Passes the load package metadata step" <|
            \_ ->
                PackageLoader.init "/project"
                    |> Tuple.second
                    |> Expect.equal (PackageLoader.ReadFile "/project" "play.json")
        , test "Retrieves necessary files" <|
            \_ ->
                PackageLoader.init "/project"
                    |> expectSideEffects testFiles
                        [ PackageLoader.ReadFile "/project" "play.json"
                        , PackageLoader.ResolveDirectories "/project/lib"
                        , PackageLoader.ReadFile "/project/lib/template_strings" "play.json"
                        ]
        ]


expectSideEffects : Dict String String -> List PackageLoader.SideEffect -> ( PackageLoader.Model, PackageLoader.SideEffect ) -> Expectation
expectSideEffects fileSystem expectedSFs ( model, sideEffect ) =
    case PackageLoader.doneState model of
        Just _ ->
            Expect.equalLists [] expectedSFs

        Nothing ->
            case sideEffect of
                PackageLoader.ReadFile path filename ->
                    case Dict.get (path ++ "/" ++ filename) fileSystem of
                        Just fileContent ->
                            expectSideEffects
                                fileSystem
                                (List.remove sideEffect expectedSFs)
                                (PackageLoader.update
                                    (PackageLoader.FileContents path filename fileContent)
                                    model
                                )

                        Nothing ->
                            Expect.fail <| "No such file: " ++ path

                PackageLoader.ResolveDirectories dir ->
                    let
                        childPaths =
                            Dict.keys fileSystem
                                |> List.filter
                                    (\path ->
                                        String.startsWith dir path
                                            && String.endsWith "play.json" path
                                    )
                                |> List.map (String.replace "/play.json" "")
                                |> List.map PackagePath.Directory
                    in
                    expectSideEffects
                        fileSystem
                        (List.remove sideEffect expectedSFs)
                        (PackageLoader.update
                            (PackageLoader.ResolvedDirectories dir childPaths)
                            model
                        )

                PackageLoader.NoOp ->
                    Expect.fail "Did not expect NoOp message."


testFiles : Dict String String
testFiles =
    Dict.fromList
        [ ( "/project/play.json"
          , """
            {
                "name": "robheghan/fnv",
                "version": "1.0.0",
                "language-version": "0.2.0",
                "exposed-modules": [
                    "fnv"
                ],
                "dependencies": {
                    "jarvis/template_strings": "1.2.0"
                },
                "package-paths": [
                    "lib/*"
                ]
            }
            """

          )
        , ( "/project/lib/template_strings/play.json"
          , """
            {
                "name": "jarvis/template_strings",
                "version": "1.2.0",
                "language-version": "0.2.0",
                "exposed-modules": [
                    "template_strings"
                ],
                "dependencies": {
                },
                "package-paths": [
                ]
            }
          """
          )
        ]