Wrap ModuleName and PackageName strings into newtypes

This commit is contained in:
klntsky 2020-07-26 22:30:42 +03:00
parent 63f651cbba
commit fd2b46e83b
19 changed files with 258 additions and 175 deletions

View File

@ -14,6 +14,7 @@ import Docs.Search.PackageIndex (PackageResult)
import Docs.Search.SearchResult (ResultInfo(..), SearchResult(..))
import Docs.Search.TypeDecoder (Constraint(..), FunDep(..), FunDeps(..), Kind(..), QualifiedName(..), Type(..), TypeArgument(..), joinForAlls, joinRows)
import Docs.Search.TypeIndex (TypeIndex)
import Docs.Search.Types (ModuleName(..), packageInfoToString)
import Prelude
@ -21,7 +22,7 @@ import Data.Array ((!!))
import Data.Array as Array
import Data.List as List
import Data.Maybe (Maybe(..), isJust, fromMaybe)
import Data.Newtype (wrap)
import Data.Newtype (wrap, unwrap)
import Data.String.CodeUnits (stripSuffix) as String
import Data.String.Common (null, trim) as String
import Data.String.Pattern (Pattern(..)) as String
@ -63,7 +64,7 @@ data Query a
data Action
= SearchResultClicked String
= SearchResultClicked ModuleName
| MoreResultsRequested
@ -145,7 +146,7 @@ handleAction = case _ of
location <- Window.location window
pathname <- Location.pathname location
pure $ isJust $
String.stripSuffix (String.Pattern $ moduleName <> ".html") pathname
String.stripSuffix (String.Pattern $ unwrap moduleName <> ".html") pathname
when onThisPage do
showPageContents
@ -254,7 +255,7 @@ renderPackageResult { name, description, repository } =
, HH.a [ HP.class_ (wrap "result__link")
, HP.href $ fromMaybe "" repository # homePageFromRepository
]
[ HH.text name ]
[ HH.text $ unwrap name ]
]
]
] <>
@ -280,9 +281,9 @@ renderModuleResult { name, package } =
[ HH.text "M" ]
, HH.a [ HP.class_ (wrap "result__link")
, HP.href $ name <> ".html"
, HP.href $ unwrap name <> ".html"
]
[ HH.text name ]
[ HH.text $ unwrap name ]
]
]
]
@ -300,7 +301,7 @@ renderSearchResult markdownIt (SearchResult result) =
[ HH.a [ HP.class_ (wrap "result__link")
, HE.onClick $ const $ Just $ SearchResultClicked result.moduleName
, HP.href $
result.moduleName <> ".html#" <>
unwrap result.moduleName <> ".html#" <>
result.hashAnchor <> ":" <> result.name
]
[ HH.text result.name ]
@ -321,7 +322,7 @@ renderSearchResult markdownIt (SearchResult result) =
, HP.title "Package"
]
[ HH.text "P" ]
, HH.text result.packageName
, HH.text $ packageInfoToString result.packageInfo
]
, HH.span [ HP.class_ (wrap "result__actions__item") ]
@ -331,7 +332,7 @@ renderSearchResult markdownIt (SearchResult result) =
, HP.title "Module"
]
[ HH.text "M" ]
, HH.text result.moduleName
, HH.text $ unwrap result.moduleName
]
]
]
@ -341,7 +342,7 @@ renderResultType
:: forall a rest
. { info :: ResultInfo
, name :: String
, moduleName :: String
, moduleName :: ModuleName
| rest
}
-> Array (HH.HTML a Action)
@ -371,7 +372,7 @@ renderResultType result =
renderValueSignature
:: forall a rest
. { moduleName :: String
. { moduleName :: ModuleName
, name :: String
| rest
}
@ -391,7 +392,7 @@ renderTypeClassSignature
, arguments :: Array TypeArgument
, superclasses :: Array Constraint
}
-> { name :: String, moduleName :: String | rest }
-> { name :: String, moduleName :: ModuleName | rest }
-> Array (HH.HTML a Action)
renderTypeClassSignature { fundeps, arguments, superclasses } { name, moduleName } =
[ keyword "class"
@ -520,14 +521,14 @@ renderType = case _ of
TypeOp qname -> renderQualifiedName true TypeLevel qname
TypeApp (TypeApp (TypeConstructor
(QualifiedName { moduleName: [ "Prim" ]
(QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Function" })) t1) t2 ->
HH.span_ [ renderType t1
, syntax " -> "
, renderType t2
]
TypeApp (TypeConstructor (QualifiedName { moduleName: [ "Prim" ]
TypeApp (TypeConstructor (QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Record" }))
row ->
renderRow false row
@ -635,6 +636,9 @@ renderRow asRow =
opening = if asRow then "( " else "{ "
closing = if asRow then " )" else " }"
primRecord :: QualifiedName
primRecord = QualifiedName { moduleNameParts: [ "Prim" ], name: "Record" }
renderConstraint
:: forall a
@ -652,18 +656,18 @@ renderQualifiedName
-> DeclLevel
-> QualifiedName
-> HH.HTML a Action
renderQualifiedName isInfix level (QualifiedName { moduleName, name })
renderQualifiedName isInfix level (QualifiedName { moduleNameParts, name })
= if isBuiltIn then
HH.text name
else
HH.a [ HE.onClick $ const $ Just $
SearchResultClicked moduleNameString
, makeHref level isInfix moduleNameString name
SearchResultClicked $ moduleName
, makeHref level isInfix moduleName name
]
[ HH.text name ]
where
moduleNameString = Array.intercalate "." moduleName
isBuiltIn = moduleName !! 0 == Just "Prim"
moduleName = ModuleName $ Array.intercalate "." $ moduleNameParts
isBuiltIn = moduleNameParts !! 0 == Just "Prim"
renderKind
@ -681,20 +685,16 @@ makeHref
:: forall t rest
. DeclLevel
-> Boolean
-> String
-> ModuleName
-> String
-> HH.IProp ( href :: String | rest ) t
makeHref level isInfix moduleName name =
HP.href $
moduleName <> ".html#" <>
unwrap moduleName <> ".html#" <>
declLevelToHashAnchor level <> ":" <>
if isInfix then "type (" <> name <> ")" else name
primRecord :: QualifiedName
primRecord = QualifiedName { moduleName: [ "Prim" ], name: "Record" }
keyword
:: forall a
. String

View File

@ -2,9 +2,10 @@ module Docs.Search.App.Sidebar where
import Docs.Search.Config (config)
import Docs.Search.ModuleIndex (PackedModuleIndex)
import Docs.Search.Types (ModuleName, PackageName)
import Docs.Search.Types (ModuleName, PackageName(..))
import Prelude
import Data.Array as Array
import Data.Lens ((.~))
import Data.Lens.Record (prop)
@ -12,7 +13,7 @@ import Data.List (foldr)
import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (Maybe(..), isJust)
import Data.Newtype (wrap)
import Data.Newtype (wrap, unwrap)
import Data.Set (Set)
import Data.Set as Set
import Data.Symbol (SProxy(..))
@ -132,7 +133,7 @@ render { moduleIndex, groupingMode, moduleNames, isIndexHTML } =
]
where
renderPackageEntry (packageName /\ modules) =
renderPackageEntry (PackageName packageName /\ modules) =
HH.li [ HP.classes [ wrap "li-package" ] ]
[ HH.details_
[ HH.summary_ [ HH.text packageName ]
@ -142,11 +143,11 @@ render { moduleIndex, groupingMode, moduleNames, isIndexHTML } =
renderModuleName moduleName =
HH.li_
[ HH.a [ HP.href (moduleName <> ".html") ]
[ HH.text moduleName ]
[ HH.a [ HP.href (unwrap moduleName <> ".html") ]
[ HH.text $ unwrap moduleName ]
]
packageList :: Array (String /\ Set ModuleName)
packageList :: Array (PackageName /\ Set ModuleName)
packageList = Map.toUnfoldable moduleIndex

View File

@ -1,10 +1,10 @@
module Docs.Search.Declarations where
import Docs.Search.DocsJson (ChildDeclType(..), ChildDeclaration(..), DeclType(..), Declaration(..), DocsJson(..), SourceSpan)
import Docs.Search.Score (Scores)
import Docs.Search.Score (Scores, getPackageScore, getPackageScoreForPackageName)
import Docs.Search.SearchResult (ResultInfo(..), SearchResult(..))
import Docs.Search.TypeDecoder (Constraint(..), QualifiedName(..), Type(..), Kind, joinForAlls)
import Docs.Search.Types (ModuleName, PackageName)
import Docs.Search.Types (ModuleName(..), PackageName(..), PackageInfo(..))
import Prelude
@ -14,7 +14,6 @@ import Data.Array as Array
import Data.Foldable (foldr)
import Data.List (List, (:))
import Data.List as List
import Data.Map as Map
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Search.Trie (Trie, alter)
@ -24,8 +23,7 @@ import Data.String.Common (toLower)
import Data.String.Pattern (Pattern(..))
newtype Declarations
= Declarations (Trie Char (List SearchResult))
newtype Declarations = Declarations (Trie Char (List SearchResult))
derive instance newtypeDeclarations :: Newtype Declarations _
derive newtype instance semigroupDeclarations :: Semigroup Declarations
@ -42,7 +40,7 @@ insertDocsJson
-> Trie Char (List SearchResult)
-> Trie Char (List SearchResult)
insertDocsJson scores (DocsJson { name, declarations }) trie
= foldr (insertDeclaration scores name) trie declarations
= foldr (insertDeclaration scores $ ModuleName name) trie declarations
insertDeclaration
@ -63,13 +61,13 @@ insertSearchResult
-> Trie Char (List SearchResult)
insertSearchResult { path, result } trie =
let path' = List.fromFoldable $ toCharArray $ toLower path in
alter path' (Just <<< updateResults) trie
where
updateResults mbOldResults
| Just oldResults <- mbOldResults =
result : oldResults
| otherwise =
List.singleton result
alter path' (Just <<< updateResults) trie
where
updateResults mbOldResults
| Just oldResults <- mbOldResults =
result : oldResults
| otherwise =
List.singleton result
-- | For each declaration, extract its own `SearchResult` and `SearchResult`s
@ -82,19 +80,17 @@ resultsForDeclaration
, result :: SearchResult
}
resultsForDeclaration scores moduleName indexEntry@(Declaration entry) =
let { info, title, sourceSpan, comments, children } = entry
{ name, declLevel } = getLevelAndName info.declType title
packageName = extractPackageName moduleName sourceSpan
in case mkInfo declLevel indexEntry of
Nothing -> mempty
Just info' ->
case mkInfo declLevel indexEntry of
Nothing -> mempty
Just info' ->
let result = SearchResult { name: title
, comments
, hashAnchor: declLevelToHashAnchor declLevel
, moduleName
, sourceSpan
, packageName
, score: fromMaybe 0 $ Map.lookup packageName scores
, packageInfo
, score:
fromMaybe 0 $ getPackageScoreForPackageName scores <$> mbPackageName
, info: info'
}
in
@ -104,8 +100,16 @@ resultsForDeclaration scores moduleName indexEntry@(Declaration entry) =
}
) <>
( List.fromFoldable children >>=
resultsForChildDeclaration scores packageName moduleName result
resultsForChildDeclaration scores packageInfo moduleName result
)
where
{ info, title, sourceSpan, comments, children } = entry
{ name, declLevel } = getLevelAndName info.declType title
packageInfo = extractPackageName moduleName sourceSpan
mbPackageName =
case packageInfo of
Package packageName -> Just packageName
_ -> Nothing
mkInfo :: DeclLevel -> Declaration -> Maybe ResultInfo
@ -188,31 +192,30 @@ getLevelAndName DeclExternKind name = { name, declLevel: KindLevel }
-- | Extract package name from `sourceSpan.name`, which contains path to
-- | the source file. If `ModuleName` string starts with `Prim.`, it's a
-- | built-in (guaranteed by the compiler).
extractPackageName :: ModuleName -> Maybe SourceSpan -> PackageName
extractPackageName moduleName _
| String.split (Pattern ".") moduleName !! 0 == Just "Prim" = "<builtin>"
extractPackageName _ Nothing = "<unknown>"
extractPackageName :: ModuleName -> Maybe SourceSpan -> PackageInfo
extractPackageName (ModuleName moduleName) _
| String.split (Pattern ".") moduleName !! 0 == Just "Prim" = Builtin
extractPackageName _ Nothing = UnknownPackage
extractPackageName _ (Just { name }) =
let dirs = String.split (Pattern "/") name
in
fromMaybe "<local package>" do
topLevelDir <- dirs !! 0
if topLevelDir == ".spago"
then dirs !! 1
else do
bowerDirIx <- Array.findIndex (_ == "bower_components") dirs
dirs !! (bowerDirIx + 1)
fromMaybe LocalPackage do
topLevelDir <- dirs !! 0
if topLevelDir == ".spago"
then Package <<< PackageName <$> dirs !! 1
else do
bowerDirIx <- Array.findIndex (_ == "bower_components") dirs
Package <<< PackageName <$> dirs !! (bowerDirIx + 1)
where dirs = String.split (Pattern "/") name
-- | Extract `SearchResults` from a `ChildDeclaration`.
resultsForChildDeclaration
:: Scores
-> PackageName
-> PackageInfo
-> ModuleName
-> SearchResult
-> ChildDeclaration
-> List { path :: String, result :: SearchResult }
resultsForChildDeclaration scores packageName moduleName parentResult
resultsForChildDeclaration scores packageInfo moduleName parentResult
child@(ChildDeclaration { title, info, comments, mbSourceSpan })
| Just resultInfo <- mkChildInfo parentResult child =
{ path: title
@ -225,8 +228,8 @@ resultsForChildDeclaration scores packageName moduleName parentResult
, hashAnchor: "v"
, moduleName
, sourceSpan: mbSourceSpan
, packageName
, score: fromMaybe 0 $ Map.lookup packageName scores
, packageInfo
, score: getPackageScore scores packageInfo
, info: resultInfo
}
} # List.singleton
@ -261,7 +264,8 @@ mkChildInfo
-- Then we construct a qualified name of the type class.
constraintClass =
QualifiedName { moduleName: String.split (wrap ".") moduleName
QualifiedName { moduleNameParts:
String.split (wrap ".") $ unwrap moduleName
, name: resultName }
-- We concatenate two lists:

View File

@ -5,7 +5,7 @@ import Docs.Search.PackageIndex (PackageIndex, PackageResult)
import Docs.Search.Score (Scores)
import Docs.Search.SearchResult (SearchResult, typeOfResult)
import Docs.Search.TypeQuery (TypeQuery(..), parseTypeQuery, penalty)
import Docs.Search.Types (PackageName, ModuleName)
import Docs.Search.Types (PackageInfo(..), PackageName(..), ModuleName(..))
import Prelude
@ -73,25 +73,25 @@ getResultScore (PackResult r) = r.score
getResultScore (MdlResult r) = r.score
getResultPackageName :: Result -> PackageName
getResultPackageName (DeclResult r) = (unwrap r).packageName
getResultPackageName (TypeResult r) = (unwrap r).packageName
getResultPackageName (PackResult r) = r.name
getResultPackageName (MdlResult r) = r.package
getResultPackageInfo :: Result -> PackageInfo
getResultPackageInfo (DeclResult r) = (unwrap r).packageInfo
getResultPackageInfo (TypeResult r) = (unwrap r).packageInfo
getResultPackageInfo (PackResult r) = Package r.name
getResultPackageInfo (MdlResult r) = Package $ r.package
getResultModuleName :: Result -> ModuleName
getResultModuleName (DeclResult r) = (unwrap r).moduleName
getResultModuleName (TypeResult r) = (unwrap r).moduleName
getResultModuleName (PackResult r) = ""
getResultModuleName (PackResult r) = ModuleName ""
getResultModuleName (MdlResult r) = r.name
getResultName :: Result -> String
getResultName (DeclResult r) = (unwrap r).name
getResultName (TypeResult r) = (unwrap r).name
getResultName (PackResult r) = r.name
getResultName (MdlResult r) = r.name
getResultName (PackResult r) = unwrap r.name
getResultName (MdlResult r) = unwrap r.name
sortByPopularity
@ -102,7 +102,7 @@ sortByPopularity
sortByPopularity { packageIndex } =
Array.sortBy (
compare `on` (getResultScore >>> negate) <>
compare `on` getResultPackageName <>
compare `on` getResultPackageInfo <>
compare `on` getResultModuleName <>
-- Identifier name comes last: we want to make sure no `Result`s are
-- equal, to avoid having unstable ordering.

View File

@ -1,16 +1,6 @@
-- | Definitions for the "search REPL".
module Docs.Search.Interactive where
import Prelude
import Data.Array as Array
import Data.Identity (Identity(..))
import Data.Maybe (fromMaybe)
import Data.Newtype (un, unwrap, wrap)
import Data.Search.Trie as Trie
import Data.String (length) as String
import Data.String.Common (split, trim) as String
import Data.Tuple (fst)
import Docs.Search.Declarations (Declarations, mkDeclarations)
import Docs.Search.DocsJson (DataDeclType(..))
import Docs.Search.Engine (mkEngineState, Result(..))
@ -26,6 +16,18 @@ import Docs.Search.Terminal (bold, cyan, green, yellow)
import Docs.Search.TypeDecoder (Constraint, FunDeps, Kind, QualifiedName, Type, TypeArgument)
import Docs.Search.TypeIndex (resultsWithTypes)
import Docs.Search.TypePrinter (keyword, showConstraint, showFunDeps, showKind, showType, showTypeArgument, space, syntax)
import Docs.Search.Types (PackageName, ModuleName, PackageInfo, packageInfoToString)
import Prelude
import Data.Array as Array
import Data.Identity (Identity(..))
import Data.Maybe (fromMaybe)
import Data.Newtype (un, unwrap, wrap)
import Data.Search.Trie as Trie
import Data.String (length) as String
import Data.String.Common (split, trim) as String
import Data.Tuple (fst)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
@ -122,33 +124,37 @@ showResult = case _ of
showSearchResult :: SearchResult -> String
showSearchResult (SearchResult result@{ name, comments, moduleName, packageName }) =
showSearchResult (SearchResult result@{ name, comments, moduleName, packageInfo }) =
showSignature result <> "\n" <>
(fromMaybe "\n" $
comments <#> \comment ->
"\n" <> leftShift 3 (String.trim comment) <> "\n\n") <>
bold (cyan (rightPad 40 packageName)) <> space <> bold (green moduleName)
bold (
cyan (rightPad 40 $ packageInfoToString packageInfo)
) <>
space <>
bold (green $ unwrap moduleName)
showPackageResult :: PackageResult -> String
showPackageResult { name, description } =
bold (cyan "package") <> " " <> bold (yellow name) <>
bold (cyan "package") <> " " <> bold (yellow $ unwrap name) <>
(description >#> \text -> "\n\n" <> leftShift 3 text <> "\n")
showModuleResult :: ModuleResult -> String
showModuleResult { name, package } =
bold (cyan "module") <> " " <> bold (green name)
bold (cyan "module") <> " " <> bold (green $ unwrap name)
showSignature ::
forall rest.
{ name :: String
, moduleName :: String
, packageName :: String
, moduleName :: ModuleName
, packageInfo :: PackageInfo
, info :: ResultInfo
| rest
}
@ -185,7 +191,7 @@ showTypeClassSignature
, arguments :: Array TypeArgument
, superclasses :: Array Constraint
}
-> { name :: String, moduleName :: String | rest }
-> { name :: String, moduleName :: ModuleName | rest }
-> String
showTypeClassSignature { fundeps, arguments, superclasses } { name, moduleName } =

View File

@ -3,9 +3,9 @@ module Docs.Search.ModuleIndex where
import Docs.Search.Config (config)
import Docs.Search.Declarations (Declarations(..))
import Docs.Search.SearchResult (SearchResult(..))
import Docs.Search.Types (ModuleName, PackageName)
import Docs.Search.Types (ModuleName, PackageName, PackageInfo(..))
import Docs.Search.Extra (stringToList)
import Docs.Search.Score (Scores, normalizePackageName)
import Docs.Search.Score (Scores)
import Prelude
@ -22,6 +22,7 @@ import Data.List (List, (:))
import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Newtype (unwrap)
import Data.Search.Trie (Trie)
import Data.Search.Trie as Trie
import Data.Set (Set)
@ -68,7 +69,9 @@ unpackModuleIndex packageModules =
-- | E.g. `"Data.Array.ST" -> ["data.array.st", "array.st", "st"]`.
extractModuleNameParts :: ModuleName -> List String
extractModuleNameParts =
foldl (\acc el -> el : map (_ <> "." <> el) acc) mempty <<< String.split (Pattern ".") <<< String.toLower
unwrap >>> String.toLower >>>
String.split (Pattern ".") >>>
foldl (\acc el -> el : map (_ <> "." <> el) acc) mempty
queryModuleIndex
@ -83,7 +86,7 @@ queryModuleIndex scores { index, modulePackages } query =
Array.nub <#>
(\name -> do
package <- Map.lookup name modulePackages
pure { name, package, score: fromMaybe 0 $ Map.lookup (normalizePackageName package) scores }) #
pure { name, package, score: fromMaybe 0 $ Map.lookup package scores }) #
Array.catMaybes
@ -97,9 +100,9 @@ mkPackedModuleIndex (Declarations trie) =
-> Map PackageName (Set ModuleName)
extract = foldr (Map.unionWith Set.union) mempty <<< map mkEntry
where
mkEntry (SearchResult { packageName, moduleName }) =
mkEntry (SearchResult { packageInfo: Package packageName, moduleName }) =
Map.singleton packageName (Set.singleton moduleName)
mkEntry _ = mempty
loadModuleIndex :: Aff PackedModuleIndex
loadModuleIndex = do

View File

@ -2,7 +2,8 @@ module Docs.Search.PackageIndex where
import Docs.Search.Config (config)
import Docs.Search.Extra (stringToList)
import Docs.Search.Score (Scores, getPackageScore, normalizePackageName)
import Docs.Search.Score (Scores, getPackageScoreForPackageName, normalizePackageName)
import Docs.Search.Types (PackageName, RawPackageName(..))
import Prelude
@ -23,10 +24,10 @@ import Web.Bower.PackageMeta (PackageMeta(..))
type PackageResult
= { name :: String
= { name :: PackageName
, description :: Maybe String
, score :: Int
, dependencies :: Array String
, dependencies :: Array PackageName
, repository :: Maybe String
}
@ -44,24 +45,26 @@ mkPackageInfo packageScores pms =
where
insert
:: PackageMeta
-> Map String PackageResult
-> Map String PackageResult
-> Map PackageName PackageResult
-> Map PackageName PackageResult
insert
(PackageMeta { name
, description
, dependencies
, devDependencies
, repository }) =
Map.insert
name
{ name
Map.insert
packageName
{ name: packageName
, description: description
, score: getPackageScore packageScores $ normalizePackageName name
, dependencies: unwrap dependencies <#> (_.packageName)
, score: getPackageScoreForPackageName packageScores packageName
, dependencies:
unwrap dependencies <#>
(_.packageName >>> RawPackageName >>> normalizePackageName)
, repository: repository <#> (_.url)
}
where packageName = normalizePackageName $ RawPackageName name
mkScoresFromPackageIndex :: PackageIndex -> Scores
mkScoresFromPackageIndex =
@ -78,7 +81,7 @@ loadPackageIndex = do
mkPackageIndex :: PackageInfo -> PackageIndex
mkPackageIndex =
Array.foldr
(\package -> Trie.insert (stringToList $ normalizePackageName package.name) package)
(\package -> Trie.insert (stringToList $ unwrap package.name) package)
mempty

View File

@ -1,6 +1,6 @@
module Docs.Search.Score where
import Docs.Search.Types (PackageName)
import Docs.Search.Types (RawPackageName(..), PackageName(..), PackageInfo(..))
import Prelude
@ -15,16 +15,9 @@ import Web.Bower.PackageMeta (Dependencies, PackageMeta)
type Scores = Map PackageName Int
getPackageScore :: Scores -> PackageName -> Int
getPackageScore _ "<builtin>" = 1000000
getPackageScore _ "<local package>" = 2000000
getPackageScore scores name = fromMaybe 0 $ Map.lookup name scores
normalizePackageName :: PackageName -> PackageName
normalizePackageName packageName =
fromMaybe packageName $ String.stripPrefix (wrap "purescript-") packageName
normalizePackageName :: RawPackageName -> PackageName
normalizePackageName (RawPackageName p) =
fromMaybe (PackageName p) $ map wrap $ String.stripPrefix (wrap "purescript-") p
-- | Construct a mapping from package names to their scores, based on number
@ -44,4 +37,16 @@ mkScores =
Array.foldr
(\dep -> Map.insertWith add dep 1)
scores
(deps # unwrap >>> map (_.packageName >>> normalizePackageName))
(deps # unwrap >>> map (_.packageName >>> RawPackageName >>> normalizePackageName))
getPackageScore :: Scores -> PackageInfo -> Int
getPackageScore scores = case _ of
Package p -> getPackageScoreForPackageName scores p
Builtin -> 100000
LocalPackage -> 200000
UnknownPackage -> 0
getPackageScoreForPackageName :: Scores -> PackageName -> Int
getPackageScoreForPackageName scores p = fromMaybe 0 $ Map.lookup p scores

View File

@ -2,6 +2,7 @@ module Docs.Search.SearchResult where
import Docs.Search.DocsJson (DataDeclType)
import Docs.Search.TypeDecoder (Constraint, FunDeps, Kind, QualifiedName, Type, TypeArgument)
import Docs.Search.Types (PackageName, PackageInfo, ModuleName)
import Prelude
@ -59,8 +60,8 @@ newtype SearchResult
{ name :: String
, comments :: Maybe String
, hashAnchor :: String
, moduleName :: String
, packageName :: String
, moduleName :: ModuleName
, packageInfo :: PackageInfo
, score :: Int
, sourceSpan :: Maybe { start :: Array Int
, end :: Array Int

View File

@ -25,20 +25,20 @@ instance showQualifiedName :: Show QualifiedName where
show = genericShow
newtype QualifiedName
= QualifiedName { moduleName :: Array String
= QualifiedName { moduleNameParts :: Array String
, name :: String
}
instance decodeJsonQualifiedName :: DecodeJson QualifiedName where
decodeJson json = do
decodeTuple
(\moduleName name -> QualifiedName { moduleName, name })
(\moduleNameParts name -> QualifiedName { moduleNameParts, name })
(mkJsonError "QualifiedName" json)
json
instance encodeJsonQualifiedName :: EncodeJson QualifiedName where
encodeJson (QualifiedName { moduleName, name }) =
encodeTuple moduleName name
encodeJson (QualifiedName { moduleNameParts, name }) =
encodeTuple moduleNameParts name
mkJsonError :: String -> Json -> (forall i. i -> String)
mkJsonError name json _ =

View File

@ -8,6 +8,7 @@ import Docs.Search.Score (Scores)
import Docs.Search.SearchResult (ResultInfo(..), SearchResult(..))
import Docs.Search.TypeDecoder (Type)
import Docs.Search.TypeQuery (TypeQuery)
import Docs.Search.Types (ModuleName(..))
import Docs.Search.TypeShape (shapeOfType, shapeOfTypeQuery, stringifyShape)
import Prelude
@ -48,7 +49,8 @@ mkTypeIndex scores docsJsons =
allResults :: Scores -> DocsJson -> Array SearchResult
allResults scores (DocsJson { name, declarations }) =
declarations >>= (resultsForDeclaration scores name >>> map (_.result) >>> Array.fromFoldable)
declarations >>= (resultsForDeclaration scores (ModuleName name) >>>
map (_.result) >>> Array.fromFoldable)
resultsWithTypes :: Scores -> DocsJson -> Array SearchResult

View File

@ -21,13 +21,13 @@ showType = case _ of
TypeOp qname -> showQualifiedName qname
TypeApp (TypeApp (TypeConstructor
(QualifiedName { moduleName: [ "Prim" ]
(QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Function" }))
t1)
t2 ->
showType t1 <> syntax " -> " <> showType t2
TypeApp (TypeConstructor (QualifiedName { moduleName: [ "Prim" ]
TypeApp (TypeConstructor (QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Record" }))
row ->
showRow false row

View File

@ -248,7 +248,7 @@ unify query type_ = go Nil (List.singleton { q: query, t: type_ })
-- * Functions
go acc ({ q: QFun q1 q2
, t: TypeApp (TypeApp (TypeConstructor
(QualifiedName { moduleName: [ "Prim" ]
(QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Function" })) t1) t2 } : rest) =
go acc ({ q: q1, t: t1 } : { q: q2, t: t2 } : rest)
go acc ({ q: q@(QFun q1 q2), t } : rest) =
@ -257,7 +257,7 @@ unify query type_ = go Nil (List.singleton { q: query, t: type_ })
-- * Rows
go acc ({ q: QApp (QConst "Record") (QRow qRows)
, t: TypeApp (TypeConstructor
(QualifiedName { moduleName: [ "Prim" ]
(QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Record" })) row } : rest) =
let { rows, ty } = joinRows row
qRowsLength = List.length qRows
@ -407,7 +407,7 @@ typeSize = go 0 <<< List.singleton
go n (TypeOp _ : rest) =
go (n + 1) rest
go n (TypeApp (TypeApp (TypeConstructor
(QualifiedName { moduleName: [ "Prim" ]
(QualifiedName { moduleNameParts: [ "Prim" ]
, name: "Function" })) t1) t2 : rest) =
go (n + 1) (t1 : t2 : rest)
go n (TypeApp q1 q2 : rest) =

View File

@ -101,7 +101,7 @@ shapeOfType ty = List.reverse $ go (pure ty) Nil
TypeWildcard ->
go rest (PVar : acc)
TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Prim"]
TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"]
, name: "Function" })) t1) t2 ->
go (t1 : t2 : rest) (PFun : acc)

View File

@ -1,5 +1,59 @@
module Docs.Search.Types where
type ModuleName = String
import Prelude
type PackageName = String
import Data.Argonaut.Decode (class DecodeJson)
import Data.Argonaut.Decode.Generic.Rep (genericDecodeJson)
import Data.Argonaut.Encode (class EncodeJson)
import Data.Argonaut.Encode.Generic.Rep (genericEncodeJson)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Newtype (class Newtype)
newtype ModuleName = ModuleName String
derive instance newtypeModuleName :: Newtype ModuleName _
derive instance genericModuleName :: Generic ModuleName _
derive newtype instance eqModuleName :: Eq ModuleName
derive newtype instance ordModuleName :: Ord ModuleName
derive newtype instance decodeJsonModuleName :: DecodeJson ModuleName
derive newtype instance encodeJsonModuleName :: EncodeJson ModuleName
-- | Non-normalized package name, e.g. `purescript-prelude` or just `prelude`.
newtype RawPackageName = RawPackageName String
derive instance newtypeRawPackageName :: Newtype RawPackageName _
-- | Normalized package name without "purescript-" prefix.
newtype PackageName = PackageName String
derive instance newtypePackageName :: Newtype PackageName _
derive newtype instance eqPackageName :: Eq PackageName
derive newtype instance ordPackageName :: Ord PackageName
derive newtype instance showPackageName :: Show PackageName
derive newtype instance decodeJsonPackageName :: DecodeJson PackageName
derive newtype instance encodeJsonPackageName :: EncodeJson PackageName
derive instance genericPackageName :: Generic PackageName _
data PackageInfo = Package PackageName | Builtin | LocalPackage | UnknownPackage
derive instance eqPackageInfo :: Eq PackageInfo
derive instance ordPackageInfo :: Ord PackageInfo
derive instance genericPackageInfo :: Generic PackageInfo _
instance showPackageInfo :: Show PackageInfo where
show = genericShow
instance decodeJsonPackageInfo :: DecodeJson PackageInfo where
decodeJson = genericDecodeJson
instance encodeJsonPackageInfo :: EncodeJson PackageInfo where
encodeJson = genericEncodeJson
packageInfoToString :: PackageInfo -> String
packageInfoToString (Package (PackageName p)) = p
packageInfoToString Builtin = "<builtin>"
packageInfoToString LocalPackage = "<local package>"
packageInfoToString UnknownPackage = "<unknown package>"

View File

@ -67,7 +67,7 @@ mainTest = do
"""
assertRight (decodeJson qualifiedName)
(QualifiedName { moduleName: ["Prim"]
(QualifiedName { moduleNameParts: ["Prim"]
, name: "Type"
}
)
@ -87,7 +87,7 @@ mainTest = do
"""
assertRight (decodeJson namedKind)
(NamedKind $ QualifiedName { moduleName: ["Prim"]
(NamedKind $ QualifiedName { moduleNameParts: ["Prim"]
, name: "Type"
}
)
@ -111,7 +111,7 @@ mainTest = do
"""
assertRight (decodeJson row)
(Row $ NamedKind $ QualifiedName { moduleName: ["Prim"]
(Row $ NamedKind $ QualifiedName { moduleNameParts: ["Prim"]
, name: "Type"
}
)
@ -154,11 +154,11 @@ mainTest = do
}
"""
assertRight (decodeJson funKind)
(FunKind (Row $ NamedKind $ QualifiedName { moduleName: ["Prim"]
(FunKind (Row $ NamedKind $ QualifiedName { moduleNameParts: ["Prim"]
, name: "Type"
}
)
(Row $ NamedKind $ QualifiedName { moduleName: ["Prim"]
(Row $ NamedKind $ QualifiedName { moduleNameParts: ["Prim"]
, name: "Type"
}
)
@ -181,7 +181,7 @@ mainTest = do
}
"""
assertRight (decodeJson constraint)
(Constraint { constraintClass: QualifiedName { moduleName: ["Prim"]
(Constraint { constraintClass: QualifiedName { moduleNameParts: ["Prim"]
, name: "Partial"
}
, constraintArgs: []
@ -230,7 +230,7 @@ mainTest = do
assertRight (decodeJson typeApp1) $
TypeApp
(TypeConstructor (QualifiedName { moduleName:
(TypeConstructor (QualifiedName { moduleNameParts:
[ "Control"
, "Monad"
, "ST"
@ -256,7 +256,7 @@ mainTest = do
}
"""
assertRight (decodeJson typeOp) $
TypeOp $ QualifiedName { moduleName: [ "Data", "NaturalTransformation" ]
TypeOp $ QualifiedName { moduleNameParts: [ "Data", "NaturalTransformation" ]
, name: "~>"
}
@ -293,7 +293,7 @@ mainTest = do
assertRight (decodeJson binaryNoParens) $
BinaryNoParensType
(TypeOp $ QualifiedName { moduleName: ["Data", "NaturalTransformation"], name: "~>" })
(TypeOp $ QualifiedName { moduleNameParts: ["Data", "NaturalTransformation"], name: "~>" })
(TypeVar "m")
(TypeVar "n")
@ -335,14 +335,14 @@ mainTest = do
assertRight (decodeJson parensInType) $
ParensInType $
TypeApp
(TypeConstructor (QualifiedName { moduleName:
(TypeConstructor (QualifiedName { moduleNameParts:
[ "Data"
, "Maybe"
],
name: "Maybe"
}
))
(TypeConstructor (QualifiedName { moduleName:
(TypeConstructor (QualifiedName { moduleNameParts:
[ "Prim"
],
name: "String"
@ -389,7 +389,7 @@ mainTest = do
assertRight (decodeJson rcons) $
RCons
"tail"
(TypeApp (TypeConstructor $ QualifiedName { moduleName: [ "Data", "Symbol" ], name: "SProxy" })
(TypeApp (TypeConstructor $ QualifiedName { moduleNameParts: [ "Data", "Symbol" ], name: "SProxy" })
(TypeVar "t"))
REmpty
@ -545,8 +545,8 @@ mainTest = do
"""
assertRight (decodeJson forallJson) $
ForAll "f"
(Just (FunKind (NamedKind (QualifiedName { moduleName: ["Prim","RowList"], name: "RowList" })) (NamedKind (QualifiedName { moduleName: ["Prim"], name: "Type" }))))
(TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Prim"], name: "Function" })) (TypeApp (TypeVar "f") (TypeVar "l"))) (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Data","List","Types"], name: "List" })) (ParensInType (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Data","Tuple"], name: "Tuple" })) (TypeConstructor (QualifiedName { moduleName: ["Prim"], name: "String" }))) (TypeConstructor (QualifiedName { moduleName: ["Prim"], name: "String" }))))))
(Just (FunKind (NamedKind (QualifiedName { moduleNameParts: ["Prim","RowList"], name: "RowList" })) (NamedKind (QualifiedName { moduleNameParts: ["Prim"], name: "Type" }))))
(TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"], name: "Function" })) (TypeApp (TypeVar "f") (TypeVar "l"))) (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Data","List","Types"], name: "List" })) (ParensInType (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Data","Tuple"], name: "Tuple" })) (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"], name: "String" }))) (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"], name: "String" }))))))
@ -558,7 +558,7 @@ mainTest = do
{"annotation":[],"tag":"ForAll","contents":["o",{"annotation":[],"tag":"ForAll","contents":["r",{"annotation":[],"tag":"ForAll","contents":["l",{"annotation":[],"tag":"ConstrainedType","contents":[{"constraintAnn":[],"constraintClass":[["Type","Data","Boolean"],"And"],"constraintArgs":[{"annotation":[],"tag":"TypeVar","contents":"l"},{"annotation":[],"tag":"TypeVar","contents":"r"},{"annotation":[],"tag":"TypeVar","contents":"o"}],"constraintData":null},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Type","Data","Boolean"],"BProxy"]},{"annotation":[],"tag":"TypeVar","contents":"l"}]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Type","Data","Boolean"],"BProxy"]},{"annotation":[],"tag":"TypeVar","contents":"r"}]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Type","Data","Boolean"],"BProxy"]},{"annotation":[],"tag":"TypeVar","contents":"o"}]}]}]}]},null]},null]},null]}
"""
assertRight (decodeJson json) $ (ForAll "o" Nothing (ForAll "r" Nothing (ForAll "l" Nothing (ConstrainedType (Constraint { constraintArgs: [(TypeVar "l"),(TypeVar "r"),(TypeVar "o")], constraintClass: (QualifiedName { moduleName: ["Type","Data","Boolean"], name: "And" }) }) (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Prim"], name: "Function" })) (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "l"))) (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Prim"], name: "Function" })) (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "r"))) (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "o"))))))))
assertRight (decodeJson json) $ (ForAll "o" Nothing (ForAll "r" Nothing (ForAll "l" Nothing (ConstrainedType (Constraint { constraintArgs: [(TypeVar "l"),(TypeVar "r"),(TypeVar "o")], constraintClass: (QualifiedName { moduleNameParts: ["Type","Data","Boolean"], name: "And" }) }) (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"], name: "Function" })) (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "l"))) (TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"], name: "Function" })) (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "r"))) (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Type","Data","Boolean"], name: "BProxy" })) (TypeVar "o"))))))))
suite "Kind encoder" do
test "FunKind" do
@ -570,4 +570,4 @@ mainTest = do
qualified :: Array String -> String -> QualifiedName
qualified moduleName name = QualifiedName { moduleName, name }
qualified moduleNameParts name = QualifiedName { moduleNameParts, name }

View File

@ -2,8 +2,11 @@ module Test.Declarations where
import Prelude
import Data.Maybe (Maybe(..))
import Docs.Search.Declarations (extractPackageName)
import Docs.Search.Types (PackageName(..), PackageInfo(..))
import Data.Maybe (Maybe(..))
import Data.Newtype (wrap)
import Test.Unit (TestSuite, suite, test)
import Test.Unit.Assert as Assert
@ -12,26 +15,26 @@ tests :: TestSuite
tests = do
suite "Declarations" do
test "extractPackageName" do
Assert.equal "<builtin>" (extractPackageName "Prim" Nothing)
Assert.equal "<builtin>" (extractPackageName "Prim.Foo" Nothing)
Assert.equal "<builtin>" (extractPackageName "Prim.Foo.Bar" Nothing)
Assert.equal "<unknown>" (extractPackageName "Primitive" Nothing)
Assert.equal "foo"
(extractPackageName "Foo" $
Assert.equal Builtin (extractPackageName (wrap "Prim") Nothing)
Assert.equal Builtin (extractPackageName (wrap "Prim.Foo") Nothing)
Assert.equal Builtin (extractPackageName (wrap "Prim.Foo.Bar") Nothing)
Assert.equal UnknownPackage (extractPackageName (wrap "Primitive") Nothing)
Assert.equal (Package $ PackageName "foo")
(extractPackageName (wrap "Foo") $
Just { start: []
, end: []
, name: ".spago/foo/src/Foo.purs"
}
)
Assert.equal "bar"
(extractPackageName "Bar" $
Assert.equal (Package $ PackageName "bar")
(extractPackageName (wrap "Bar") $
Just { start: []
, end: []
, name: "/path/to/somewhere/bower_components/bar/src/Bar.purs"
}
)
Assert.equal "<local package>"
(extractPackageName "Bar" $
Assert.equal LocalPackage
(extractPackageName (wrap "Bar") $
Just { start: []
, end: []
, name: "/path/to/somewhere/src/Bar.purs"

View File

@ -5,6 +5,7 @@ import Docs.Search.ModuleIndex (extractModuleNameParts)
import Prelude
import Data.List as List
import Data.Newtype (wrap)
import Test.Unit (TestSuite, suite, test)
import Test.Unit.Assert as Assert
@ -14,11 +15,11 @@ tests = do
suite "ModuleIndex" do
test "test #0" do
Assert.equal (extractModuleNameParts "Data.Array.ST") (
Assert.equal (extractModuleNameParts $ wrap "Data.Array.ST") (
List.fromFoldable [ "st", "array.st", "data.array.st" ]
)
test "test #1" do
Assert.equal (extractModuleNameParts "Foo") (
Assert.equal (extractModuleNameParts $ wrap "Foo") (
List.fromFoldable [ "foo" ]
)

View File

@ -245,7 +245,7 @@ tests = do
c2 = constr (qname [""] "GenericEq") [TypeVar "rep"]
fun t1 t2 =
TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleName: ["Prim"]
TypeApp (TypeApp (TypeConstructor (QualifiedName { moduleNameParts: ["Prim"]
, name: "Function" })) t1) t2
type_ =
ForAll "a" Nothing $
@ -391,7 +391,7 @@ nl :: forall t5 t6. Foldable t6 => t5 -> t6 t5 -> NonEmptyList t5
nl x rst = NonEmptyList.cons' x $ List.fromFoldable rst
unitType :: Type
unitType = TypeConstructor (QualifiedName { moduleName: []
unitType = TypeConstructor (QualifiedName { moduleNameParts: []
, name: "Unit"
})
@ -399,7 +399,7 @@ countFreeVars :: TypeQuery -> Int
countFreeVars = getFreeVariables >>> Set.size
qname :: Array String -> String -> QualifiedName
qname m n = QualifiedName { moduleName: m, name: n }
qname m n = QualifiedName { moduleNameParts: m, name: n }
constr :: QualifiedName -> Array Type -> Constraint
constr c a = Constraint { constraintClass: c, constraintArgs: a }