Prechádzať zdrojové kódy

Complete parsing of Unified Top Card

jherve 1 rok pred
rodič
commit
23cdea439f
1 zmenil súbory, kde vykonal 112 pridanie a 12 odobranie
  1. 112 12
      src/LinkedIn/JobsUnifiedTopCard.purs

+ 112 - 12
src/LinkedIn/JobsUnifiedTopCard.purs

@@ -1,27 +1,49 @@
 module LinkedIn.JobsUnifiedTopCard where
 
+import Control.Alt
 import Prelude
 
 import Data.Either (Either(..), hush)
 import Data.Generic.Rep (class Generic)
-import Data.List.Types (NonEmptyList)
+import Data.List.Types (NonEmptyList(..))
 import Data.Maybe (Maybe(..))
 import Data.Show.Generic (genericShow)
-import LinkedIn (DetachedNode)
-import LinkedIn.Types (Parser)
-import LinkedIn.Utils (detachNonEmptyTextChild, queryAndDetachMany, queryAndDetachOne, queryOneAndParse)
+import Debug (trace)
+import LinkedIn (DetachedNode(..))
+import LinkedIn.Types (ParseError(..), Parser)
+import LinkedIn.Utils (detachNonEmptyTextChild, parseDetachedNode, queryAndDetachMany, queryAndDetachOne, queryManyAndParse, queryOneAndParse)
 
 data JobsUnifiedTopCardElement = JobsUnifiedTopCardElement {
   header :: DetachedNode,
-  primaryDescription :: Maybe TopCardPrimaryDescription
+  primaryDescription :: Maybe TopCardPrimaryDescription,
+  insights :: Maybe (NonEmptyList TopCardInsight),
+  actions :: Maybe (NonEmptyList TopCardAction)
 }
 
 data TopCardPrimaryDescription = TopCardPrimaryDescription {
   link :: DetachedNode,
   text :: DetachedNode,
-  neutral :: Maybe (NonEmptyList DetachedNode)
+  tvmText :: Maybe (NonEmptyList DetachedNode)
 }
 
+data TopCardInsight = TopCardInsight {
+  icon :: DetachedNode,
+  content :: TopCardInsightContent
+}
+
+data TopCardInsightContent =
+  TopCardInsightContentSingle DetachedNode
+  | TopCardInsightContentSecondary {primary :: DetachedNode, secondary :: NonEmptyList TopCardSecondaryInsight}
+  | TopCardInsightContentButton DetachedNode
+
+data TopCardSecondaryInsight =
+  TopCardSecondaryInsightNested DetachedNode
+  | TopCardSecondaryInsightPlain DetachedNode
+
+-- External application : <button id="ember74"  class="jobs-apply-button artdeco-button artdeco-button--3 artdeco-button--primary ember-view artdeco-button--icon-right" role="link">
+-- LinkedIn Applcation : <button id="ember115" class="jobs-apply-button artdeco-button artdeco-button--3 artdeco-button--primary ember-view" data-job-id="3786945580">
+data TopCardAction = TopCardActionApplyButton DetachedNode
+
 derive instance Generic JobsUnifiedTopCardElement _
 derive instance Eq JobsUnifiedTopCardElement
 instance Show JobsUnifiedTopCardElement where
@@ -32,25 +54,103 @@ derive instance Eq TopCardPrimaryDescription
 instance Show TopCardPrimaryDescription where
   show = genericShow
 
+derive instance Generic TopCardInsight _
+derive instance Eq TopCardInsight
+instance Show TopCardInsight where
+  show = genericShow
+
+derive instance Generic TopCardInsightContent _
+derive instance Eq TopCardInsightContent
+instance Show TopCardInsightContent where
+  show = genericShow
+
+derive instance Generic TopCardSecondaryInsight _
+derive instance Eq TopCardSecondaryInsight
+instance Show TopCardSecondaryInsight where
+  show = genericShow
+
+derive instance Generic TopCardAction _
+derive instance Eq TopCardAction
+instance Show TopCardAction where
+  show = genericShow
+
+parseTopCardAction :: Parser TopCardAction
+parseTopCardAction n = do
+  self <- parseDetachedNode n
+
+  pure $ ado
+    s <- self
+  in TopCardActionApplyButton s
+
+parseTopCardSecondaryInsight :: Parser TopCardSecondaryInsight
+parseTopCardSecondaryInsight n = do
+  nested <- queryAndDetachOne ":scope span[aria-hidden=true]" n
+  plain <- parseDetachedNode n
+
+  pure $ case nested, plain of
+    Right p@(DetachedElement _), _ -> Right $ TopCardSecondaryInsightNested p
+    _, Right p@(DetachedElement _) -> Right $ TopCardSecondaryInsightPlain p
+    _, _ -> Left TextNotFoundError
+
+parseTopCardInsightContent :: Parser TopCardInsightContent
+parseTopCardInsightContent n = do
+  primary <- queryAndDetachOne ":scope > span:first-child span[aria-hidden=true]" n
+  secondary <- queryManyAndParse
+    ":scope > span.job-details-jobs-unified-top-card__job-insight-view-model-secondary"
+    parseTopCardSecondaryInsight
+    n
+  self <- parseDetachedNode n
+
+  pure $ case primary, secondary, self of
+    _, _, Right b@(DetachedElement {tag: "BUTTON"}) -> Right $ TopCardInsightContentButton b
+    Right p@(DetachedElement _), Right s, _ -> Right $ TopCardInsightContentSecondary {primary: p, secondary: s}
+    _, _, Right el@(DetachedElement _) -> Right $ TopCardInsightContentSingle el
+    _, _, _ -> Left TextNotFoundError
+
+parseTopCardInsight :: Parser TopCardInsight
+parseTopCardInsight n = do
+  icon <- queryAndDetachOne ":scope li-icon" n
+  svg <- queryAndDetachOne ":scope svg" n
+  content <- queryOneAndParse ":scope > span" parseTopCardInsightContent n
+  actionButton <- queryOneAndParse ":scope > button" parseTopCardInsightContent n
+
+  pure $ ado
+    i <- icon <|> svg
+    c <- content <|> actionButton
+  in TopCardInsight {icon: i, content: c}
+
 parseTopCardPrimaryDescription :: Parser TopCardPrimaryDescription
 parseTopCardPrimaryDescription n = do
   link <- queryAndDetachOne ":scope > a" n
   text <- detachNonEmptyTextChild n
-  neutral <- queryAndDetachMany "span.tvm__text--neutral" n
-  
+  tvmText <- queryAndDetachMany "span.tvm__text" n
+
   pure $ ado
     l <- link
     t <- text
-  in TopCardPrimaryDescription {link: l, text: t, neutral: hush neutral}
+  in TopCardPrimaryDescription {link: l, text: t, tvmText: hush tvmText}
 
 parseJobsUnifiedTopCardElement :: Parser JobsUnifiedTopCardElement
 parseJobsUnifiedTopCardElement n = do
   h1 <- queryAndDetachOne "h1.job-details-jobs-unified-top-card__job-title" n
-  primary <- queryOneAndParse 
-    "div.job-details-jobs-unified-top-card__primary-description-container > div" 
+  primary <- queryOneAndParse
+    "div.job-details-jobs-unified-top-card__primary-description-container > div"
     parseTopCardPrimaryDescription
     n
+  insights <- queryManyAndParse
+    "li.job-details-jobs-unified-top-card__job-insight"
+    parseTopCardInsight
+    n
+  actions <- queryManyAndParse
+    ".mt5 button"
+    parseTopCardAction
+    n
 
   pure $ ado
     h <- h1
-  in JobsUnifiedTopCardElement {header: h, primaryDescription: hush primary}
+  in JobsUnifiedTopCardElement {
+    header: h,
+    primaryDescription: hush primary,
+    insights: hush insights,
+    actions: hush actions
+  }