mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-25 02:34:36 +03:00
184 lines
5.9 KiB
Elm
184 lines
5.9 KiB
Elm
module Docs.UpToDateReadmeLinks exposing (rule)
|
|
|
|
{-|
|
|
|
|
@docs rule
|
|
|
|
-}
|
|
|
|
import Docs.Utils.Link as Link exposing (Link)
|
|
import Elm.Package
|
|
import Elm.Project
|
|
import Elm.Syntax.Node exposing (Node(..))
|
|
import Elm.Version
|
|
import Review.Fix as Fix
|
|
import Review.Rule as Rule exposing (Error, Rule)
|
|
|
|
|
|
{-| Reports links in the `README.md` that point to this project's package documentation on <https://package.elm-lang.org/>,
|
|
where the version is set to `latest` or a different version than the current version of the package.
|
|
|
|
🔧 Running with `--fix` will automatically remove all the reported errors.
|
|
|
|
config =
|
|
[ Docs.UpToDateReadmeLinks.rule
|
|
]
|
|
|
|
The problem with linking to `latest` is that if you release a new version later,
|
|
the users who read the README for the older version will be directed to a version
|
|
where the module/function/section you pointed to may not exist anymore.
|
|
|
|
This rule ensures that you always use the correct version in all of your releases,
|
|
and that you do not forget to update the links.
|
|
|
|
This rule provides automatic fixes, so you won't to do the tedious job of updating
|
|
the links yourself.
|
|
|
|
**NOTE**: Just make sure to run tests between bumping the version of the package
|
|
and publishing the package. Otherwise the link for a given version could link to a previous one.
|
|
|
|
**NOTE**: A similar rule would be useful for links inside the modules. I'll be working on that too!
|
|
|
|
|
|
## Try it out
|
|
|
|
You can try this rule out by running the following command:
|
|
|
|
```bash
|
|
elm-review --template jfmengels/elm-review-documentation/example --rules Docs.UpToDateReadmeLinks
|
|
```
|
|
|
|
-}
|
|
rule : Rule
|
|
rule =
|
|
Rule.newProjectRuleSchema "Docs.UpToDateReadmeLinks" initialProjectContext
|
|
|> Rule.withElmJsonProjectVisitor elmJsonVisitor
|
|
|> Rule.withReadmeProjectVisitor readmeVisitor
|
|
|> Rule.fromProjectRuleSchema
|
|
|
|
|
|
type alias ProjectContext =
|
|
Maybe
|
|
{ projectName : String
|
|
, version : String
|
|
}
|
|
|
|
|
|
initialProjectContext : ProjectContext
|
|
initialProjectContext =
|
|
Nothing
|
|
|
|
|
|
|
|
-- elm.json VISITOR
|
|
|
|
|
|
elmJsonVisitor : Maybe { a | project : Elm.Project.Project } -> ProjectContext -> ( List nothing, ProjectContext )
|
|
elmJsonVisitor maybeProject _ =
|
|
case maybeProject |> Maybe.map .project of
|
|
Just (Elm.Project.Package pkg) ->
|
|
( []
|
|
, Just
|
|
{ projectName = Elm.Package.toString pkg.name
|
|
, version = Elm.Version.toString pkg.version
|
|
}
|
|
)
|
|
|
|
_ ->
|
|
( [], Nothing )
|
|
|
|
|
|
|
|
-- README VISITOR
|
|
|
|
|
|
readmeVisitor : Maybe { readmeKey : Rule.ReadmeKey, content : String } -> ProjectContext -> ( List (Error scope), ProjectContext )
|
|
readmeVisitor maybeReadme maybeContext =
|
|
case ( maybeReadme, maybeContext ) of
|
|
( Just { readmeKey, content }, Just context ) ->
|
|
( reportErrorsForReadme context readmeKey content, maybeContext )
|
|
|
|
_ ->
|
|
( [], maybeContext )
|
|
|
|
|
|
reportErrorsForReadme : { projectName : String, version : String } -> Rule.ReadmeKey -> String -> List (Error scope)
|
|
reportErrorsForReadme context readmeKey content =
|
|
content
|
|
|> Link.findLinks 0 []
|
|
|> List.concatMap (reportError context readmeKey)
|
|
|
|
|
|
reportError : { projectName : String, version : String } -> Rule.ReadmeKey -> Node Link -> List (Error scope)
|
|
reportError context readmeKey (Node range link) =
|
|
case link.file of
|
|
Link.ModuleTarget moduleName ->
|
|
[ Rule.errorForReadmeWithFix readmeKey
|
|
{ message = "Found relative link to a module in README"
|
|
, details =
|
|
[ "Relative links to other modules from the README don't work when looking at the docs from GitHub or the likes."
|
|
, "I suggest to run elm-review --fix to change the link to an absolute link."
|
|
]
|
|
}
|
|
range
|
|
[ Fix.replaceRangeBy range <| "https://package.elm-lang.org/packages/" ++ context.projectName ++ "/" ++ context.version ++ "/" ++ String.join "-" moduleName ++ formatSlug link.slug ]
|
|
]
|
|
|
|
Link.ReadmeTarget ->
|
|
if link.startsWithDotSlash then
|
|
[ Rule.errorForReadmeWithFix readmeKey
|
|
{ message = "Found relative link from and to README"
|
|
, details =
|
|
[ "Links from and to README that start with \"./\" will not work on all places on GitHub or the likes."
|
|
, "I suggest to remove the leading \"./\"."
|
|
]
|
|
}
|
|
range
|
|
(case link.slug of
|
|
Just slug ->
|
|
[ Fix.replaceRangeBy range ("#" ++ slug) ]
|
|
|
|
Nothing ->
|
|
[]
|
|
)
|
|
]
|
|
|
|
else
|
|
[]
|
|
|
|
Link.PackagesTarget { name, version, subTarget } ->
|
|
if context.projectName == name && context.version /= version then
|
|
[ Rule.errorForReadmeWithFix readmeKey
|
|
{ message = "Link does not point to the current version of the package"
|
|
, details = [ "I suggest to run elm-review --fix to get the correct link." ]
|
|
}
|
|
range
|
|
[ Fix.replaceRangeBy range <| "https://package.elm-lang.org/packages/" ++ name ++ "/" ++ context.version ++ "/" ++ formatSubTarget subTarget ++ formatSlug link.slug ]
|
|
]
|
|
|
|
else
|
|
[]
|
|
|
|
Link.External _ ->
|
|
[]
|
|
|
|
|
|
formatSubTarget : Link.SubTarget -> String
|
|
formatSubTarget subTarget =
|
|
case subTarget of
|
|
Link.ModuleSubTarget moduleName ->
|
|
String.join "-" moduleName ++ "/"
|
|
|
|
Link.ReadmeSubTarget ->
|
|
""
|
|
|
|
|
|
formatSlug : Maybe String -> String
|
|
formatSlug maybeSlug =
|
|
case maybeSlug of
|
|
Just slug ->
|
|
"#" ++ slug
|
|
|
|
Nothing ->
|
|
""
|