Play

Check-in [6092e67f02]
Login
Overview
Comment:PackageLoader now resolves the modules of each package.
Timelines: family | ancestors | descendants | both | modules
Files: files | file ages | folders
SHA3-256: 6092e67f023f9fb103ca41e259aee277d3f8591fe6b1553e19ddc5f505ea9aeb
User & Date: robin.hansen on 2021-02-27 15:35:22
Other Links: branch diff | manifest | tags
Context
2021-02-27
15:58
Strip .play suffix from files before trying to convert to a ModuleName. check-in: 03c71127f3 user: robin.hansen tags: modules
15:35
PackageLoader now resolves the modules of each package. check-in: 6092e67f02 user: robin.hansen tags: modules
2021-02-25
14:55
Refactor model of PackageLoader. check-in: 3485ad3ca9 user: robin.hansen tags: modules
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/PackageLoader.elm from [62165525df] to [f6bdf34c6b].

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
..
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
..
96
97
98
99
100
101
102



103
104
105
106
107
108
109
...
117
118
119
120
121
122
123

124
125
126
127
128
129
130
...
131
132
133
134
135
136
137
138


139
140
141
142
143
144
145
...
153
154
155
156
157
158
159
160


161
162
163
164
165
166
167
168




















































    , 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
    = Initializing SideEffect
    | LoadingMetadata State (List PackagePath) SideEffect

    | Done State
    | Failed Problem


type alias State =
    { rootPackage : PackageInfo
    , dependentPackages : Dict String PackageInfo
    }


type alias PackageInfo =
    { path : String
    , metadata : PackageMetadata

    }


emptyState : PackageInfo -> State
emptyState rootPackage =
    { rootPackage = rootPackage
    , dependentPackages = Dict.empty
    }


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



type SideEffect
    = ReadFile String String
    | ResolveDirectories String



init : String -> Model
init projectDirPath =
    Initializing
        (ReadFile projectDirPath "play.json")

................................................................................
                    case Json.decodeString PackageMetadata.decoder content of
                        Ok metadata ->
                            let
                                state =
                                    emptyState
                                        { path = path
                                        , metadata = metadata

                                        }

                                pathsToLoad =
                                    List.map (PackagePath.prefix path) metadata.packagePaths
                            in
                            case pathsToLoad of
                                [] ->
                                    Done state

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

                                (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                                    LoadingMetadata state pathsToLoad <|
................................................................................

                _ ->
                    Failed (InvalidPackageMetadata "todo: path" "Wrong message on initialization")

        LoadingMetadata state remainingPaths _ ->
            loadingMetadataUpdate msg state remainingPaths




        Done _ ->
            model

        Failed _ ->
            model


................................................................................
                        updatedState =
                            { state
                                | dependentPackages =
                                    Dict.insert
                                        (PackageName.toString metadata.name)
                                        { path = path
                                        , metadata = metadata

                                        }
                                        state.dependentPackages
                            }

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

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



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

                        (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                            LoadingMetadata updatedState pathsToLoad <|
................................................................................
                pathsToLoad =
                    remainingPaths
                        |> List.remove (PackagePath.AllDirectoriesInDirectory parentDir)
                        |> (++) paths
            in
            case pathsToLoad of
                [] ->
                    Done state



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

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



























































>



>




>
>





>













>













>





>







 







>







|







 







>
>
>







 







>







 







|
>
>







 







|
>
>








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    , init
    , update
    )

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


type Problem
    = InvalidPackageMetadata String String
    | UnknownMessageForState String
    | InternalError String


type Model
    = Initializing SideEffect
    | LoadingMetadata State (List PackagePath) SideEffect
    | ResolvingModulePaths State (List PackageInfo) SideEffect
    | Done State
    | Failed Problem


type alias State =
    { rootPackage : PackageInfo
    , dependentPackages : Dict String PackageInfo
    }


type alias PackageInfo =
    { path : String
    , metadata : PackageMetadata
    , modules : List ModuleName
    }


emptyState : PackageInfo -> State
emptyState rootPackage =
    { rootPackage = rootPackage
    , dependentPackages = Dict.empty
    }


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


type SideEffect
    = ReadFile String String
    | ResolveDirectories String
    | ResolvePackageModules String String


init : String -> Model
init projectDirPath =
    Initializing
        (ReadFile projectDirPath "play.json")

................................................................................
                    case Json.decodeString PackageMetadata.decoder content of
                        Ok metadata ->
                            let
                                state =
                                    emptyState
                                        { path = path
                                        , metadata = metadata
                                        , modules = []
                                        }

                                pathsToLoad =
                                    List.map (PackagePath.prefix path) metadata.packagePaths
                            in
                            case pathsToLoad of
                                [] ->
                                    ResolvingModulePaths state [] (ResolvePackageModules (PackageName.toString metadata.name) path)

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

                                (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                                    LoadingMetadata state pathsToLoad <|
................................................................................

                _ ->
                    Failed (InvalidPackageMetadata "todo: path" "Wrong message on initialization")

        LoadingMetadata state remainingPaths _ ->
            loadingMetadataUpdate msg state remainingPaths

        ResolvingModulePaths state remainingPackages _ ->
            resolvingModulePathsUpdate msg state remainingPackages

        Done _ ->
            model

        Failed _ ->
            model


................................................................................
                        updatedState =
                            { state
                                | dependentPackages =
                                    Dict.insert
                                        (PackageName.toString metadata.name)
                                        { path = path
                                        , metadata = metadata
                                        , modules = []
                                        }
                                        state.dependentPackages
                            }

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

................................................................................
                        pathsToLoad =
                            remainingPaths
                                |> List.remove (PackagePath.Directory path)
                                |> (++) absolutePackagePaths
                    in
                    case pathsToLoad of
                        [] ->
                            ResolvingModulePaths updatedState
                                (Dict.values updatedState.dependentPackages)
                                (ResolvePackageModules (PackageName.toString state.rootPackage.metadata.name) state.rootPackage.path)

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

                        (PackagePath.AllDirectoriesInDirectory nextPathDir) :: _ ->
                            LoadingMetadata updatedState pathsToLoad <|
................................................................................
                pathsToLoad =
                    remainingPaths
                        |> List.remove (PackagePath.AllDirectoriesInDirectory parentDir)
                        |> (++) paths
            in
            case pathsToLoad of
                [] ->
                    ResolvingModulePaths state
                        (Dict.values state.dependentPackages)
                        (ResolvePackageModules (PackageName.toString state.rootPackage.metadata.name) state.rootPackage.path)

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

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

        _ ->
            Failed <| UnknownMessageForState "LoadingMetadata"


resolvingModulePathsUpdate : Msg -> State -> List PackageInfo -> Model
resolvingModulePathsUpdate msg state remainingPackages =
    case msg of
        ResolvedPackageModules packageName modules ->
            let
                rootPackage =
                    state.rootPackage

                moduleNameResults =
                    List.map ModuleName.fromString modules
                        |> Result.combine

                updatedRemainingPackages =
                    List.filter (\p -> PackageName.toString p.metadata.name /= packageName) remainingPackages

                nextStep newState =
                    case updatedRemainingPackages of
                        nextPackage :: _ ->
                            ResolvingModulePaths newState
                                updatedRemainingPackages
                                (ResolvePackageModules (PackageName.toString nextPackage.metadata.name) nextPackage.path)

                        [] ->
                            Done newState
            in
            case moduleNameResults of
                Err _ ->
                    Failed <| InternalError <| "Invalid module names for package " ++ packageName

                Ok moduleNames ->
                    if packageName == PackageName.toString state.rootPackage.metadata.name then
                        nextStep { state | rootPackage = { rootPackage | modules = moduleNames } }

                    else
                        case Dict.get packageName state.dependentPackages of
                            Nothing ->
                                Failed <| InternalError <| "Package " ++ packageName ++ " doesn't exist"

                            Just package ->
                                nextStep
                                    { state
                                        | dependentPackages =
                                            Dict.insert packageName { package | modules = moduleNames } state.dependentPackages
                                    }

        _ ->
            Failed <| UnknownMessageForState "ResolvingModulePaths"

Modified tests/Test/PackageLoader.elm from [5f7b23a79d] to [23b0e67b68].

18
19
20
21
22
23
24


25
26
27
28
29
30
31
..
64
65
66
67
68
69
70





















71
72
73
74
75
76
77
..
79
80
81
82
83
84
85



86
87
88
89
90
91
92
        , 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 -> Expectation
expectSideEffects fileSystem expectedSFs model =
    case getSideEffect model of
................................................................................
                        fileSystem
                        (List.remove sideEffect expectedSFs)
                        (PackageLoader.update
                            (PackageLoader.ResolvedDirectories dir childPaths)
                            model
                        )























getSideEffect : PackageLoader.Model -> Maybe PackageLoader.SideEffect
getSideEffect model =
    case model of
        PackageLoader.Done _ ->
            Nothing

................................................................................
            Nothing

        PackageLoader.Initializing sf ->
            Just sf

        PackageLoader.LoadingMetadata _ _ sf ->
            Just sf





testFiles : Dict String String
testFiles =
    Dict.fromList
        [ ( "/project/play.json"
          , """







>
>







 







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







 







>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
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
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        , 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"
                        , PackageLoader.ResolvePackageModules "robheghan/fnv" "/project"
                        , PackageLoader.ResolvePackageModules "jarvis/template_strings" "/project/lib/template_strings"
                        ]
        ]


expectSideEffects : Dict String String -> List PackageLoader.SideEffect -> PackageLoader.Model -> Expectation
expectSideEffects fileSystem expectedSFs model =
    case getSideEffect model of
................................................................................
                        fileSystem
                        (List.remove sideEffect expectedSFs)
                        (PackageLoader.update
                            (PackageLoader.ResolvedDirectories dir childPaths)
                            model
                        )

                PackageLoader.ResolvePackageModules packageName packagePath ->
                    let
                        srcPath =
                            packagePath ++ "/src/"

                        childPaths =
                            Dict.keys fileSystem
                                |> List.filter
                                    (\path ->
                                        String.startsWith srcPath path
                                    )
                                |> List.map (String.replace srcPath "")
                    in
                    expectSideEffects
                        fileSystem
                        (List.remove sideEffect expectedSFs)
                        (PackageLoader.update
                            (PackageLoader.ResolvedPackageModules packageName childPaths)
                            model
                        )


getSideEffect : PackageLoader.Model -> Maybe PackageLoader.SideEffect
getSideEffect model =
    case model of
        PackageLoader.Done _ ->
            Nothing

................................................................................
            Nothing

        PackageLoader.Initializing sf ->
            Just sf

        PackageLoader.LoadingMetadata _ _ sf ->
            Just sf

        PackageLoader.ResolvingModulePaths _ _ sf ->
            Just sf


testFiles : Dict String String
testFiles =
    Dict.fromList
        [ ( "/project/play.json"
          , """