Explorar o código

Add support for projects, skills, and artdeco tabs

jherve hai 1 ano
pai
achega
3505b4d025

+ 15 - 2
src/Content.purs

@@ -12,7 +12,10 @@ import Effect (Effect)
 import Effect.Class.Console (logShow)
 import Effect.Console (log)
 import LinkedIn.ArtDecoCard (parseArtDecoCard)
-import LinkedIn.Profile.WorkExperience (fromUI)
+import LinkedIn.ArtDecoTab (parseArtDecoTab)
+import LinkedIn.Profile.Project as PP
+import LinkedIn.Profile.WorkExperience as PWE
+import LinkedIn.Profile.Skill as PS
 import Yoga.Tree (Tree, showTree)
 
 main :: Effect Unit
@@ -38,7 +41,17 @@ main = do
       case parsed of
         Left l -> logShow l
         Right p -> do
-          logShow $ fromUI p
+          logShow $ PWE.fromUI p
+          logShow $ PP.fromUI p
+  case artDecoTabs of
+    Nothing -> log "nothing"
+    Just l -> do
+      parsed <- (\(LinkedInUIElement _ n) -> parseArtDecoTab n) $ NEL.head l
+      logShow parsed
+      case parsed of
+        Left l -> logShow l
+        Right p -> do
+          logShow $ PS.fromUI p
 
 maybeShowTree ∷ Maybe (NonEmptyList LinkedInUIElement) → Effect String
 maybeShowTree Nothing = pure "nope"

+ 117 - 0
src/LinkedIn/ArtDecoTab.purs

@@ -0,0 +1,117 @@
+module LinkedIn.ArtDecoTab where
+
+import Prelude
+
+import Data.Either (Either(..), hush)
+import Data.Generic.Rep (class Generic)
+import Data.List.NonEmpty (NonEmptyList)
+import Data.Maybe (Maybe)
+import Data.Show.Generic (genericShow)
+import LinkedIn (DetachedNode)
+import LinkedIn.Types (Parser)
+import LinkedIn.Utils (queryAndDetachMany, queryAndDetachOne, queryManyAndParse, queryOneAndParse)
+
+
+data ArtDecoTabElement = ArtDecoTabElement {
+  pvs_entity :: ArtDecoPvsEntity
+}
+
+data ArtDecoPvsEntity = ArtDecoPvsEntity {
+  side :: Unit,
+  center :: ArtDecoCenter
+}
+
+data ArtDecoCenter = ArtDecoCenter {
+  header :: ArtDecoCenterHeader,
+  content :: ArtDecoCenterContent
+}
+
+data ArtDecoCenterHeader = ArtDecoCenterHeader {
+  bold :: DetachedNode,
+  normal :: Maybe DetachedNode,
+  light :: Maybe (NonEmptyList DetachedNode)
+}
+
+data ArtDecoCenterContent = ArtDecoCenterContent (NonEmptyList ArtDecoPvsEntitySubComponent)
+
+data ArtDecoPvsEntitySubComponent = ArtDecoPvsEntitySubComponent (Maybe DetachedNode)
+
+
+derive instance Generic ArtDecoPvsEntitySubComponent _
+derive instance Eq ArtDecoPvsEntitySubComponent
+instance Show ArtDecoPvsEntitySubComponent where
+  show = genericShow
+
+derive instance Generic ArtDecoCenterContent _
+derive instance Eq ArtDecoCenterContent
+instance Show ArtDecoCenterContent where
+  show = genericShow
+
+derive instance Generic ArtDecoCenterHeader _
+derive instance Eq ArtDecoCenterHeader
+instance Show ArtDecoCenterHeader where
+  show = genericShow
+
+derive instance Generic ArtDecoCenter _
+derive instance Eq ArtDecoCenter
+instance Show ArtDecoCenter where
+  show = genericShow
+
+derive instance Generic ArtDecoPvsEntity _
+derive instance Eq ArtDecoPvsEntity
+instance Show ArtDecoPvsEntity where
+  show = genericShow
+
+derive instance Generic ArtDecoTabElement _
+derive instance Eq ArtDecoTabElement
+instance Show ArtDecoTabElement where
+  show = genericShow
+
+
+parseArtDecoPvsEntitySubComponent ∷ Parser ArtDecoPvsEntitySubComponent
+parseArtDecoPvsEntitySubComponent n = do
+  content <- queryAndDetachOne "span[aria-hidden=true]" n
+  pure $ Right $ ArtDecoPvsEntitySubComponent $ hush content
+
+parseArtDecoCenterContent ∷ Parser ArtDecoCenterContent
+parseArtDecoCenterContent n = do
+  list <- queryManyAndParse ":scope > ul > li" parseArtDecoPvsEntitySubComponent n
+  pure $ ado
+    l <- list
+  in ArtDecoCenterContent l
+
+parseArtDecoCenterHeader :: Parser ArtDecoCenterHeader
+parseArtDecoCenterHeader n = do
+  bold <- queryAndDetachOne ":scope div.t-bold > span[aria-hidden=true]" n
+  normal <- queryAndDetachOne ":scope span.t-normal:not(t-black--light) > span[aria-hidden=true]" n
+  light <- queryAndDetachMany ":scope span.t-black--light > span[aria-hidden=true]" n
+
+  pure $ ado
+    b <- bold
+  in ArtDecoCenterHeader {bold: b, normal: hush normal, light: hush light}
+
+parseArtDecoCenter :: Parser ArtDecoCenter
+parseArtDecoCenter n = do
+  header <- queryOneAndParse ":scope > div" parseArtDecoCenterHeader n
+  content <- queryOneAndParse ":scope > div.pvs-entity__sub-components" parseArtDecoCenterContent n
+
+  pure $ ado
+    h <- header
+    c <- content
+  in ArtDecoCenter {header: h, content: c}
+
+parseArtDecoPvsEntity :: Parser ArtDecoPvsEntity
+parseArtDecoPvsEntity n = do
+  center <- queryOneAndParse ":scope > div.display-flex" parseArtDecoCenter n
+
+  pure $ ado
+    c <- center
+  in ArtDecoPvsEntity {side: unit, center: c}
+
+parseArtDecoTab :: Parser ArtDecoTabElement
+parseArtDecoTab n = do
+  pvs <- queryOneAndParse ":scope div.pvs-entity--padded" parseArtDecoPvsEntity n
+
+  pure $ ado
+    p <- pvs
+  in ArtDecoTabElement {pvs_entity: p}

+ 77 - 0
src/LinkedIn/Profile/Project.purs

@@ -0,0 +1,77 @@
+module LinkedIn.Profile.Project where
+
+import LinkedIn.Profile.Utils
+import LinkedIn.UIElements.Parser
+import Prelude
+
+import Data.Either (Either, note)
+import Data.Foldable (findMap)
+import Data.Generic.Rep (class Generic)
+import Data.List (List)
+import Data.List.NonEmpty (NonEmptyList)
+import Data.List.NonEmpty as NEL
+import Data.Maybe (Maybe(..))
+import Data.Show.Generic (genericShow)
+import Debug (trace)
+import LinkedIn (DetachedNode)
+import LinkedIn.ArtDecoCard (ArtDecoCardElement(..), ArtDecoCenter(..), ArtDecoCenterContent(..), ArtDecoCenterHeader(..), ArtDecoPvsEntity(..), ArtDecoPvsEntitySubComponent(..))
+import LinkedIn.UIElements.Types (Duration, TimeSpan, UIElement(..))
+import Parsing (ParseError)
+
+data Project = Project {
+  name :: String,
+  timeSpan :: Maybe TimeSpan,
+  description :: Maybe String
+}
+
+derive instance Generic Project _
+instance Show Project where
+  show = genericShow
+
+fromUI ∷ ArtDecoCardElement → Either String Project
+fromUI (ArtDecoCardElement {
+  pvs_entity: ArtDecoPvsEntity {
+    center: ArtDecoCenter {
+      header: ArtDecoCenterHeader {
+        bold,
+        normal,
+        light
+      },
+      content: ArtDecoCenterContent subComponents
+    }
+  }
+}) = ado
+    name <- note "No position found" $ findMap extractName bold'
+  in
+    Project {
+    name,
+    timeSpan: maybeExtractFromMaybe extractTimeSpan normal',
+    description: maybeGetInList extractDescription content' 0
+  } where
+  bold' = toUIElement bold
+
+  content' :: List (Either ParseError UIElement)
+  content' = map toUIElement subC
+    where subC = NEL.catMaybes $ map (\(ArtDecoPvsEntitySubComponent c) -> c) subComponents :: List (DetachedNode)
+
+  normal' :: Maybe (Either ParseError UIElement)
+  normal' = toUIElement <$> normal
+
+  light' :: Maybe (NonEmptyList (Either ParseError UIElement))
+  light' = (map toUIElement) <$> light
+
+extractName :: UIElement -> Maybe String
+extractName = case _ of
+  UIPlainText str -> Just str
+  _ -> Nothing
+
+extractTimeSpan ∷ UIElement → Maybe TimeSpan
+extractTimeSpan = case _ of
+  UITimeSpan s -> Just s
+  UIDotSeparated (UITimeSpan s) _ -> Just s
+  _ -> Nothing
+
+extractDescription ∷ UIElement → Maybe String
+extractDescription = case _ of
+  UIPlainText d -> Just d
+  _ -> Nothing

+ 39 - 0
src/LinkedIn/Profile/Skill.purs

@@ -0,0 +1,39 @@
+module LinkedIn.Profile.Skill where
+
+import LinkedIn.Profile.Utils
+import LinkedIn.UIElements.Parser
+import Prelude
+
+import Data.Either (Either, note)
+import Data.Foldable (findMap)
+import Data.Generic.Rep (class Generic)
+import Data.Maybe (Maybe(..))
+import Data.Show.Generic (genericShow)
+import LinkedIn.ArtDecoTab (ArtDecoTabElement(..), ArtDecoCenter(..), ArtDecoCenterHeader(..), ArtDecoPvsEntity(..))
+import LinkedIn.UIElements.Types (UIElement(..))
+
+data Skill = Skill {
+  name :: String
+}
+
+derive instance Generic Skill _
+instance Show Skill where
+  show = genericShow
+
+fromUI ∷ ArtDecoTabElement → Either String Skill
+fromUI (ArtDecoTabElement {
+  pvs_entity: ArtDecoPvsEntity {
+    center: ArtDecoCenter {
+      header: ArtDecoCenterHeader { bold }
+    }
+  }
+}) = ado
+    name <- note "No position found" $ findMap extractName bold'
+  in
+    Skill { name } where
+  bold' = toUIElement bold
+
+extractName :: UIElement -> Maybe String
+extractName = case _ of
+  UIPlainText str -> Just str
+  _ -> Nothing