Просмотр исходного кода

Create a hierarchy of LinkedIn.UI modules

jherve 1 год назад
Родитель
Сommit
6b35394667

+ 3 - 3
src/Content.purs

@@ -14,9 +14,9 @@ import LinkedIn.Page.JobOffer as PageJ
 import LinkedIn.Page.Projects as PageP
 import LinkedIn.Page.Projects as PageP
 import LinkedIn.Page.Skills as PageS
 import LinkedIn.Page.Skills as PageS
 import LinkedIn.Page.WorkExperiences as PageWE
 import LinkedIn.Page.WorkExperiences as PageWE
-import LinkedIn.Profile.Utils (fromDetachedToUI, fromNodeToDetached)
 import LinkedIn.QueryRunner (QueryRunner', runQuery)
 import LinkedIn.QueryRunner (QueryRunner', runQuery)
-import LinkedIn.UIElements.Types (UIElement)
+import LinkedIn.UI.Elements.Parser (fromDetachedToUI)
+import LinkedIn.UI.Elements.Types (UIElement)
 import Web.DOM (Document, Node)
 import Web.DOM (Document, Node)
 
 
 main :: Effect Unit
 main :: Effect Unit
@@ -34,7 +34,7 @@ main = do
 
 
 extractData ∷ ∀ t a. Traversable t ⇒ (t UIElement → Either String a) → t Node → Effect (Either String a)
 extractData ∷ ∀ t a. Traversable t ⇒ (t UIElement → Either String a) → t Node → Effect (Either String a)
 extractData parsePageUI n = do
 extractData parsePageUI n = do
-  d <- fromNodeToDetached n
+  d <- traverse toDetached n
   pure $ case fromDetachedToUI d of
   pure $ case fromDetachedToUI d of
       Left l -> Left l
       Left l -> Left l
       Right ui -> parsePageUI ui
       Right ui -> parsePageUI ui

+ 4 - 2
src/LinkedIn/Jobs/JobOffer.purs

@@ -7,8 +7,10 @@ import Data.Generic.Rep (class Generic)
 import Data.Lens (findOf)
 import Data.Lens (findOf)
 import Data.Maybe (Maybe(..), isJust)
 import Data.Maybe (Maybe(..), isJust)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
-import LinkedIn.JobsUnifiedTopCard (JobsUnifiedTopCardElement, TopCardInsight(..), TopCardInsightContent(..), _top_to_action_buttons, _top_to_insights, toHeader, toPrimaryDescriptionLink, toPrimaryDescriptionText)
-import LinkedIn.UIElements.Types (JobFlexibility, UIElement(..), UIString(..))
+import LinkedIn.UI.Components.JobsUnifiedTopCard (JobsUnifiedTopCardElement, TopCardInsight(..), TopCardInsightContent(..), _top_to_action_buttons, _top_to_insights, toHeader, toPrimaryDescriptionLink, toPrimaryDescriptionText)
+import LinkedIn.UI.Basic.Types (JobFlexibility)
+import LinkedIn.UI.Strings.Types (UIString(..))
+import LinkedIn.UI.Elements.Types (UIElement(..))
 
 
 data JobOffer = JobOffer {
 data JobOffer = JobOffer {
   title :: String,
   title :: String,

+ 2 - 2
src/LinkedIn/Page/JobOffer.purs

@@ -9,9 +9,9 @@ import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import LinkedIn.Jobs.JobOffer (JobOffer)
 import LinkedIn.Jobs.JobOffer (JobOffer)
 import LinkedIn.Jobs.JobOffer as JJO
 import LinkedIn.Jobs.JobOffer as JJO
-import LinkedIn.JobsUnifiedTopCard (JobsUnifiedTopCardElement, queryJobsUnifiedTopCardElement)
+import LinkedIn.UI.Components.JobsUnifiedTopCard (JobsUnifiedTopCardElement, queryJobsUnifiedTopCardElement)
 import LinkedIn.QueryRunner (QueryRunner', subQueryOne)
 import LinkedIn.QueryRunner (QueryRunner', subQueryOne)
-import LinkedIn.UIElements.Types (UIElement)
+import LinkedIn.UI.Elements.Types (UIElement)
 import Web.DOM (Document, Node)
 import Web.DOM (Document, Node)
 
 
 data JobOfferPage a = JobOfferPage (JobsUnifiedTopCardElement a)
 data JobOfferPage a = JobOfferPage (JobsUnifiedTopCardElement a)

+ 2 - 2
src/LinkedIn/Page/Projects.purs

@@ -8,11 +8,11 @@ import Data.Generic.Rep (class Generic)
 import Data.List.Types (NonEmptyList)
 import Data.List.Types (NonEmptyList)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
-import LinkedIn.ArtDecoCard (ArtDecoCardElement, queryArtDecoCard)
+import LinkedIn.UI.Components.ArtDecoCard (ArtDecoCardElement, queryArtDecoCard)
 import LinkedIn.Profile.Project (Project)
 import LinkedIn.Profile.Project (Project)
 import LinkedIn.Profile.Project as PP
 import LinkedIn.Profile.Project as PP
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
-import LinkedIn.UIElements.Types (UIElement)
+import LinkedIn.UI.Elements.Types (UIElement)
 import Web.DOM (Document, Node)
 import Web.DOM (Document, Node)
 
 
 data ProjectsPage a = ProjectsPage (NonEmptyList (ArtDecoCardElement a))
 data ProjectsPage a = ProjectsPage (NonEmptyList (ArtDecoCardElement a))

+ 2 - 2
src/LinkedIn/Page/Skills.purs

@@ -8,11 +8,11 @@ import Data.Generic.Rep (class Generic)
 import Data.List.Types (NonEmptyList)
 import Data.List.Types (NonEmptyList)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
-import LinkedIn.ArtDecoTab (ArtDecoTabElement, queryArtDecoTab)
+import LinkedIn.UI.Components.ArtDecoTab (ArtDecoTabElement, queryArtDecoTab)
 import LinkedIn.Profile.Skill (Skill)
 import LinkedIn.Profile.Skill (Skill)
 import LinkedIn.Profile.Skill as PS
 import LinkedIn.Profile.Skill as PS
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
-import LinkedIn.UIElements.Types (UIElement)
+import LinkedIn.UI.Elements.Types (UIElement)
 import Web.DOM (Document, Node)
 import Web.DOM (Document, Node)
 
 
 data SkillsPage a = SkillsPage (NonEmptyList (ArtDecoTabElement a))
 data SkillsPage a = SkillsPage (NonEmptyList (ArtDecoTabElement a))

+ 2 - 2
src/LinkedIn/Page/WorkExperiences.purs

@@ -8,11 +8,11 @@ import Data.Generic.Rep (class Generic)
 import Data.List.Types (NonEmptyList)
 import Data.List.Types (NonEmptyList)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverse, traverseDefault)
-import LinkedIn.ArtDecoCard (ArtDecoCardElement, queryArtDecoCard)
+import LinkedIn.UI.Components.ArtDecoCard (ArtDecoCardElement, queryArtDecoCard)
 import LinkedIn.Profile.WorkExperience (WorkExperience)
 import LinkedIn.Profile.WorkExperience (WorkExperience)
 import LinkedIn.Profile.WorkExperience as PWE
 import LinkedIn.Profile.WorkExperience as PWE
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
 import LinkedIn.QueryRunner (QueryRunner', subQueryMany)
-import LinkedIn.UIElements.Types (UIElement)
+import LinkedIn.UI.Elements.Types (UIElement)
 import Web.DOM (Document, Node)
 import Web.DOM (Document, Node)
 
 
 data WorkExperiencesPage a = WorkExperiencesPage (NonEmptyList (ArtDecoCardElement a))
 data WorkExperiencesPage a = WorkExperiencesPage (NonEmptyList (ArtDecoCardElement a))

+ 4 - 2
src/LinkedIn/Profile/Project.purs

@@ -7,8 +7,10 @@ import Data.Generic.Rep (class Generic)
 import Data.List as L
 import Data.List as L
 import Data.Maybe (Maybe(..))
 import Data.Maybe (Maybe(..))
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
-import LinkedIn.ArtDecoCard (ArtDecoCardElement, toCenterContent, toHeaderBold, toHeaderNormal)
-import LinkedIn.UIElements.Types (TimeSpan, UIElement(..), UIString(..))
+import LinkedIn.UI.Components.ArtDecoCard (ArtDecoCardElement, toCenterContent, toHeaderBold, toHeaderNormal)
+import LinkedIn.UI.Basic.Types (TimeSpan)
+import LinkedIn.UI.Strings.Types (UIString(..))
+import LinkedIn.UI.Elements.Types (UIElement(..))
 
 
 data Project = Project {
 data Project = Project {
   name :: String,
   name :: String,

+ 3 - 2
src/LinkedIn/Profile/Skill.purs

@@ -6,8 +6,9 @@ import Data.Either (Either, note)
 import Data.Generic.Rep (class Generic)
 import Data.Generic.Rep (class Generic)
 import Data.Maybe (Maybe(..))
 import Data.Maybe (Maybe(..))
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
-import LinkedIn.ArtDecoTab (ArtDecoTabElement, toHeaderBold)
-import LinkedIn.UIElements.Types (UIElement(..), UIString(..))
+import LinkedIn.UI.Components.ArtDecoTab (ArtDecoTabElement, toHeaderBold)
+import LinkedIn.UI.Strings.Types (UIString(..))
+import LinkedIn.UI.Elements.Types (UIElement(..))
 
 
 data Skill = Skill {
 data Skill = Skill {
   name :: String
   name :: String

+ 4 - 2
src/LinkedIn/Profile/WorkExperience.purs

@@ -8,8 +8,10 @@ import Data.Generic.Rep (class Generic)
 import Data.List as L
 import Data.List as L
 import Data.Maybe (Maybe(..))
 import Data.Maybe (Maybe(..))
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
-import LinkedIn.ArtDecoCard (ArtDecoCardElement, toCenterContent, toHeaderBold, toHeaderLight, toHeaderNormal)
-import LinkedIn.UIElements.Types (Duration, TimeSpan, UIElement(..), UIString(..))
+import LinkedIn.UI.Components.ArtDecoCard (ArtDecoCardElement, toCenterContent, toHeaderBold, toHeaderLight, toHeaderNormal)
+import LinkedIn.UI.Basic.Types (Duration, TimeSpan)
+import LinkedIn.UI.Strings.Types (UIString(..))
+import LinkedIn.UI.Elements.Types (UIElement(..))
 
 
 data WorkExperience = WorkExperience {
 data WorkExperience = WorkExperience {
   position :: String,
   position :: String,

+ 3 - 40
src/LinkedIn/UIElements/Parser.purs

@@ -1,11 +1,10 @@
-module LinkedIn.UIElements.Parser where
+module LinkedIn.UI.Basic.Parser where
 
 
 import Prelude
 import Prelude
 
 
 import Control.Alt ((<|>))
 import Control.Alt ((<|>))
 import Data.Array as A
 import Data.Array as A
 import Data.Date (Month(..), Year)
 import Data.Date (Month(..), Year)
-import Data.Either (hush)
 import Data.Enum (toEnum)
 import Data.Enum (toEnum)
 import Data.Int (fromNumber)
 import Data.Int (fromNumber)
 import Data.List (List(..), (:))
 import Data.List (List(..), (:))
@@ -18,8 +17,8 @@ import Data.Maybe (Maybe(..))
 import Data.String as S
 import Data.String as S
 import Data.String.CodePoints (codePointFromChar)
 import Data.String.CodePoints (codePointFromChar)
 import Data.Tuple (Tuple(..))
 import Data.Tuple (Tuple(..))
-import LinkedIn.UIElements.Types (Duration(..), JobFlexibility(..), MonthYear(..), MonthYearOrToday(..), TimeSpan(..), UIString(..))
-import Parsing (Parser, ParserT, fail, liftMaybe, runParser)
+import LinkedIn.UI.Basic.Types (Duration(..), JobFlexibility(..), MonthYear(..), MonthYearOrToday(..), TimeSpan(..))
+import Parsing (Parser, ParserT, fail)
 import Parsing.Combinators (choice, try)
 import Parsing.Combinators (choice, try)
 import Parsing.String (char, rest, string)
 import Parsing.String (char, rest, string)
 import Parsing.String.Basic (intDecimal, number, space, takeWhile)
 import Parsing.String.Basic (intDecimal, number, space, takeWhile)
@@ -144,27 +143,6 @@ stringWithoutCommaP = takeWhile (\c -> c /= codePointFromChar ',')
 stringWithoutMedianDotP :: Parser String String
 stringWithoutMedianDotP :: Parser String String
 stringWithoutMedianDotP = takeWhile (\c -> c /= codePointFromChar '·' && c /= codePointFromChar '•')
 stringWithoutMedianDotP = takeWhile (\c -> c /= codePointFromChar '·' && c /= codePointFromChar '•')
 
 
-uiStringP :: Parser String UIString
-uiStringP = (try uiStringdotSeparatedP) <|> uiStringSingleP
-
-uiStringWithoutMedianDotP ∷ Parser String UIString
-uiStringWithoutMedianDotP = do
-  s <- rest
-  liftMaybe (\_ -> "nope") $ hush $ runParser s uiStringSingleP
-
-uiStringdotSeparatedP ∷ Parser String UIString
-uiStringdotSeparatedP = do
-  Tuple s1 s2 <- medianDotSeparated
-
-  let
-    intoUiElement :: String -> Parser String UIString
-    intoUiElement s = liftMaybe (\_ -> "could not convert to ui element") $ hush $ runParser s uiStringSingleP
-
-  s1' <- intoUiElement s1
-  s2' <- intoUiElement s2
-
-  pure $ UIStringDotSeparated s1' s2'
-
 sepBy2 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
 sepBy2 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
 sepBy2 p sep = do
 sepBy2 p sep = do
   a0 <- p
   a0 <- p
@@ -180,18 +158,3 @@ medianDotSeparated = do
   a0 <- stringWithoutMedianDotP
   a0 <- stringWithoutMedianDotP
   a1 <- medianDotP *> rest
   a1 <- medianDotP *> rest
   pure $ Tuple (S.trim a0) (S.trim a1)
   pure $ Tuple (S.trim a0) (S.trim a1)
-
-uiStringSingleP ∷ Parser String UIString
-uiStringSingleP = (try uiStringDurationP) <|> (try uiStringTimeSpanP) <|> (try uiStringJobFlexP) <|> uiStringPlainP
-
-uiStringDurationP ∷ Parser String UIString
-uiStringDurationP = UIStringDuration <$> durationP
-
-uiStringTimeSpanP ∷ Parser String UIString
-uiStringTimeSpanP = UIStringTimeSpan <$> timeSpanP
-
-uiStringJobFlexP ∷ Parser String UIString
-uiStringJobFlexP = UIStringJobFlex <$> jobFlexP
-
-uiStringPlainP ∷ Parser String UIString
-uiStringPlainP = UIStringPlain <$> rest

+ 1 - 25
src/LinkedIn/UIElements/Types.purs

@@ -1,10 +1,9 @@
-module LinkedIn.UIElements.Types where
+module LinkedIn.UI.Basic.Types where
 
 
 import Prelude
 import Prelude
 
 
 import Data.Date (Month, Year)
 import Data.Date (Month, Year)
 import Data.Generic.Rep (class Generic)
 import Data.Generic.Rep (class Generic)
-import Data.Maybe (Maybe)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 
 
 data MonthYear = MonthYear Month Year
 data MonthYear = MonthYear Month Year
@@ -41,26 +40,3 @@ derive instance Eq JobFlexibility
 derive instance Generic JobFlexibility _
 derive instance Generic JobFlexibility _
 instance Show JobFlexibility where
 instance Show JobFlexibility where
   show = genericShow
   show = genericShow
-
-data UIString =
-  UIStringDuration Duration
-  | UIStringTimeSpan TimeSpan
-  | UIStringJobFlex JobFlexibility
-  | UIStringPlain String
-  | UIStringDotSeparated UIString UIString
-
-derive instance Eq UIString
-derive instance Generic UIString _
-instance Show UIString where
-  show (UIStringDotSeparated ui1 ui2) = "(UIStringDotSeparated " <> show ui1 <> show ui2 <> ")"
-  show u = genericShow u
-
-data UIElement =
-  UIElement UIString
-  | UILink String UIString
-  | UIButton {role :: Maybe String, label :: UIString, mainClass :: Maybe String}
-  | UIIcon String
-
-derive instance Generic UIElement _
-instance Show UIElement where
-  show = genericShow

+ 1 - 1
src/LinkedIn/ArtDeco.purs

@@ -1,4 +1,4 @@
-module LinkedIn.ArtDeco where
+module LinkedIn.UI.Components.ArtDeco where
 
 
 import Prelude
 import Prelude
 
 

+ 2 - 2
src/LinkedIn/ArtDecoCard.purs

@@ -1,4 +1,4 @@
-module LinkedIn.ArtDecoCard where
+module LinkedIn.UI.Components.ArtDecoCard where
 
 
 import Prelude
 import Prelude
 
 
@@ -13,7 +13,7 @@ import Data.Maybe (Maybe)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import Data.Tuple (Tuple(..))
 import Data.Tuple (Tuple(..))
-import LinkedIn.ArtDeco (ArtDecoPvsEntity, _pvs_to_header_bold, _pvs_to_header_light, _pvs_to_header_normal, _pvs_to_subcomponents, queryArtDecoPvsEntity)
+import LinkedIn.UI.Components.ArtDeco (ArtDecoPvsEntity, _pvs_to_header_bold, _pvs_to_header_light, _pvs_to_header_normal, _pvs_to_subcomponents, queryArtDecoPvsEntity)
 import LinkedIn.QueryRunner (QueryRunner, subQueryOne)
 import LinkedIn.QueryRunner (QueryRunner, subQueryOne)
 import Type.Proxy (Proxy(..))
 import Type.Proxy (Proxy(..))
 import Web.DOM (Node)
 import Web.DOM (Node)

+ 2 - 2
src/LinkedIn/ArtDecoTab.purs

@@ -1,4 +1,4 @@
-module LinkedIn.ArtDecoTab where
+module LinkedIn.UI.Components.ArtDecoTab where
 
 
 import Prelude
 import Prelude
 
 
@@ -13,7 +13,7 @@ import Data.Maybe (Maybe)
 import Data.Show.Generic (genericShow)
 import Data.Show.Generic (genericShow)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import Data.Traversable (class Traversable, sequence, traverseDefault)
 import Data.Tuple (Tuple(..))
 import Data.Tuple (Tuple(..))
-import LinkedIn.ArtDeco (ArtDecoPvsEntity, _pvs_to_header_bold, _pvs_to_header_light, _pvs_to_header_normal, _pvs_to_subcomponents, queryArtDecoPvsEntity)
+import LinkedIn.UI.Components.ArtDeco (ArtDecoPvsEntity, _pvs_to_header_bold, _pvs_to_header_light, _pvs_to_header_normal, _pvs_to_subcomponents, queryArtDecoPvsEntity)
 import LinkedIn.QueryRunner (QueryRunner, subQueryOne)
 import LinkedIn.QueryRunner (QueryRunner, subQueryOne)
 import Type.Proxy (Proxy(..))
 import Type.Proxy (Proxy(..))
 import Web.DOM (Node)
 import Web.DOM (Node)

+ 1 - 1
src/LinkedIn/JobsUnifiedTopCard.purs

@@ -1,4 +1,4 @@
-module LinkedIn.JobsUnifiedTopCard where
+module LinkedIn.UI.Components.JobsUnifiedTopCard where
 
 
 import Prelude
 import Prelude
 
 

+ 4 - 9
src/LinkedIn/Profile/Utils.purs

@@ -1,4 +1,4 @@
-module LinkedIn.Profile.Utils where
+module LinkedIn.UI.Elements.Parser where
 
 
 import Prelude
 import Prelude
 
 
@@ -7,15 +7,10 @@ import Data.Either (Either(..))
 import Data.List as L
 import Data.List as L
 import Data.Maybe (Maybe(..))
 import Data.Maybe (Maybe(..))
 import Data.Traversable (class Traversable, traverse)
 import Data.Traversable (class Traversable, traverse)
-import Effect (Effect)
-import LinkedIn.DetachedNode (DetachedNode(..), toDetached)
-import LinkedIn.UIElements.Parser (uiStringP)
-import LinkedIn.UIElements.Types (UIElement(..))
+import LinkedIn.DetachedNode (DetachedNode(..))
+import LinkedIn.UI.Strings.Parser (uiStringP)
+import LinkedIn.UI.Elements.Types (UIElement(..))
 import Parsing (ParseError(..), initialPos, runParser)
 import Parsing (ParseError(..), initialPos, runParser)
-import Web.DOM (Node)
-
-fromNodeToDetached ∷ ∀ t. Traversable t ⇒ t Node → Effect (t DetachedNode)
-fromNodeToDetached = traverse toDetached
 
 
 fromDetachedToUI ∷ ∀ t. Traversable t ⇒ t DetachedNode → Either String (t UIElement)
 fromDetachedToUI ∷ ∀ t. Traversable t ⇒ t DetachedNode → Either String (t UIElement)
 fromDetachedToUI el = case traverse toUIElement el of
 fromDetachedToUI el = case traverse toUIElement el of

+ 18 - 0
src/LinkedIn/UI/Elements/Types.purs

@@ -0,0 +1,18 @@
+module LinkedIn.UI.Elements.Types where
+
+import Prelude
+
+import Data.Generic.Rep (class Generic)
+import Data.Maybe (Maybe)
+import Data.Show.Generic (genericShow)
+import LinkedIn.UI.Strings.Types (UIString)
+
+data UIElement =
+  UIElement UIString
+  | UILink String UIString
+  | UIButton {role :: Maybe String, label :: UIString, mainClass :: Maybe String}
+  | UIIcon String
+
+derive instance Generic UIElement _
+instance Show UIElement where
+  show = genericShow

+ 48 - 0
src/LinkedIn/UI/Strings/Parser.purs

@@ -0,0 +1,48 @@
+module LinkedIn.UI.Strings.Parser where
+
+import Prelude
+
+import Control.Alt ((<|>))
+import Data.Either (hush)
+import Data.Tuple (Tuple(..))
+import LinkedIn.UI.Basic.Parser (durationP, jobFlexP, medianDotSeparated, timeSpanP)
+import LinkedIn.UI.Strings.Types (UIString(..))
+import Parsing (Parser, liftMaybe, runParser)
+import Parsing.Combinators (try)
+import Parsing.String (rest)
+
+uiStringP :: Parser String UIString
+uiStringP = (try uiStringdotSeparatedP) <|> uiStringSingleP
+
+uiStringWithoutMedianDotP ∷ Parser String UIString
+uiStringWithoutMedianDotP = do
+  s <- rest
+  liftMaybe (\_ -> "nope") $ hush $ runParser s uiStringSingleP
+
+uiStringdotSeparatedP ∷ Parser String UIString
+uiStringdotSeparatedP = do
+  Tuple s1 s2 <- medianDotSeparated
+
+  let
+    intoUiElement :: String -> Parser String UIString
+    intoUiElement s = liftMaybe (\_ -> "could not convert to ui element") $ hush $ runParser s uiStringSingleP
+
+  s1' <- intoUiElement s1
+  s2' <- intoUiElement s2
+
+  pure $ UIStringDotSeparated s1' s2'
+
+uiStringSingleP ∷ Parser String UIString
+uiStringSingleP = (try uiStringDurationP) <|> (try uiStringTimeSpanP) <|> (try uiStringJobFlexP) <|> uiStringPlainP
+
+uiStringDurationP ∷ Parser String UIString
+uiStringDurationP = UIStringDuration <$> durationP
+
+uiStringTimeSpanP ∷ Parser String UIString
+uiStringTimeSpanP = UIStringTimeSpan <$> timeSpanP
+
+uiStringJobFlexP ∷ Parser String UIString
+uiStringJobFlexP = UIStringJobFlex <$> jobFlexP
+
+uiStringPlainP ∷ Parser String UIString
+uiStringPlainP = UIStringPlain <$> rest

+ 20 - 0
src/LinkedIn/UI/Strings/Types.purs

@@ -0,0 +1,20 @@
+module LinkedIn.UI.Strings.Types where
+
+import Prelude
+
+import Data.Generic.Rep (class Generic)
+import Data.Show.Generic (genericShow)
+import LinkedIn.UI.Basic.Types (Duration, JobFlexibility, TimeSpan)
+
+data UIString =
+  UIStringDuration Duration
+  | UIStringTimeSpan TimeSpan
+  | UIStringJobFlex JobFlexibility
+  | UIStringPlain String
+  | UIStringDotSeparated UIString UIString
+
+derive instance Eq UIString
+derive instance Generic UIString _
+instance Show UIString where
+  show (UIStringDotSeparated ui1 ui2) = "(UIStringDotSeparated " <> show ui1 <> show ui2 <> ")"
+  show u = genericShow u

+ 4 - 4
test/ArtDecoCard.purs

@@ -11,16 +11,16 @@ import Data.Maybe (Maybe(..), fromJust)
 import Data.NonEmpty (NonEmpty(..))
 import Data.NonEmpty (NonEmpty(..))
 import Data.Traversable (traverse)
 import Data.Traversable (traverse)
 import Effect (Effect)
 import Effect (Effect)
-import LinkedIn.ArtDeco (ArtDecoCenter(..), ArtDecoCenterContent(..), ArtDecoCenterHeader(..), ArtDecoPvsEntity(..), ArtDecoPvsEntitySubComponent(..))
-import LinkedIn.ArtDecoCard (ArtDecoCardElement(..))
+import LinkedIn.UI.Components.ArtDeco (ArtDecoCenter(..), ArtDecoCenterContent(..), ArtDecoCenterHeader(..), ArtDecoPvsEntity(..), ArtDecoPvsEntitySubComponent(..))
+import LinkedIn.UI.Components.ArtDecoCard (ArtDecoCardElement(..))
 import LinkedIn.DetachedNode (DetachedNode(..), toDetached)
 import LinkedIn.DetachedNode (DetachedNode(..), toDetached)
 import LinkedIn.Page.WorkExperiences (WorkExperiencesPage(..))
 import LinkedIn.Page.WorkExperiences (WorkExperiencesPage(..))
 import LinkedIn.Page.WorkExperiences as PageWE
 import LinkedIn.Page.WorkExperiences as PageWE
-import LinkedIn.Profile.Utils (fromDetachedToUI)
 import LinkedIn.Profile.WorkExperience (WorkExperience(..))
 import LinkedIn.Profile.WorkExperience (WorkExperience(..))
 import LinkedIn.Profile.WorkExperience as PWE
 import LinkedIn.Profile.WorkExperience as PWE
 import LinkedIn.QueryRunner (runQuery)
 import LinkedIn.QueryRunner (runQuery)
-import LinkedIn.UIElements.Types (Duration(..), TimeSpan(..))
+import LinkedIn.UI.Basic.Types (Duration(..), TimeSpan(..))
+import LinkedIn.UI.Elements.Parser (fromDetachedToUI)
 import Node.JsDom (jsDomFromFile)
 import Node.JsDom (jsDomFromFile)
 import Partial.Unsafe (unsafePartial)
 import Partial.Unsafe (unsafePartial)
 import Test.Assert (assert, assertEqual)
 import Test.Assert (assert, assertEqual)

+ 3 - 3
test/JobsUnifiedTopCard.purs

@@ -12,12 +12,12 @@ import Effect (Effect)
 import LinkedIn.DetachedNode (DetachedNode(..), toDetached)
 import LinkedIn.DetachedNode (DetachedNode(..), toDetached)
 import LinkedIn.Jobs.JobOffer (JobOffer(..))
 import LinkedIn.Jobs.JobOffer (JobOffer(..))
 import LinkedIn.Jobs.JobOffer as JJO
 import LinkedIn.Jobs.JobOffer as JJO
-import LinkedIn.JobsUnifiedTopCard (JobsUnifiedTopCardElement(..), TopCardAction(..), TopCardInsight(..), TopCardInsightContent(..), TopCardPrimaryDescription(..), TopCardSecondaryInsight(..))
+import LinkedIn.UI.Components.JobsUnifiedTopCard (JobsUnifiedTopCardElement(..), TopCardAction(..), TopCardInsight(..), TopCardInsightContent(..), TopCardPrimaryDescription(..), TopCardSecondaryInsight(..))
 import LinkedIn.Page.JobOffer (JobOfferPage(..))
 import LinkedIn.Page.JobOffer (JobOfferPage(..))
 import LinkedIn.Page.JobOffer as PageJO
 import LinkedIn.Page.JobOffer as PageJO
-import LinkedIn.Profile.Utils (fromDetachedToUI)
 import LinkedIn.QueryRunner (runQuery)
 import LinkedIn.QueryRunner (runQuery)
-import LinkedIn.UIElements.Types (JobFlexibility(..))
+import LinkedIn.UI.Basic.Types (JobFlexibility(..))
+import LinkedIn.UI.Elements.Parser (fromDetachedToUI)
 import Node.JsDom (jsDomFromFile)
 import Node.JsDom (jsDomFromFile)
 import Partial.Unsafe (unsafePartial)
 import Partial.Unsafe (unsafePartial)
 import Test.Assert (assert, assertEqual)
 import Test.Assert (assert, assertEqual)

+ 4 - 2
test/UIStringParser.purs

@@ -8,8 +8,10 @@ import Prelude
 import Data.Date (Month(..))
 import Data.Date (Month(..))
 import Data.Either (Either(..))
 import Data.Either (Either(..))
 import Effect (Effect)
 import Effect (Effect)
-import LinkedIn.UIElements.Parser (durationP, monthYearP, timeSpanP, uiStringDurationP, uiStringdotSeparatedP)
-import LinkedIn.UIElements.Types (Duration(..), TimeSpan(..), UIString(..))
+import LinkedIn.UI.Basic.Parser (durationP, monthYearP, timeSpanP)
+import LinkedIn.UI.Basic.Types (Duration(..), TimeSpan(..))
+import LinkedIn.UI.Strings.Parser (uiStringDurationP, uiStringdotSeparatedP)
+import LinkedIn.UI.Strings.Types (UIString(..))
 import Parsing (ParseError(..), Position(..), runParser)
 import Parsing (ParseError(..), Position(..), runParser)
 import Test.Assert (assertEqual)
 import Test.Assert (assertEqual)
 import Test.Utils (toMonthYear')
 import Test.Utils (toMonthYear')

+ 2 - 2
test/Utils.purs

@@ -5,8 +5,8 @@ import Prelude
 import Data.Date (Month)
 import Data.Date (Month)
 import Data.Int (toNumber)
 import Data.Int (toNumber)
 import Data.Maybe (fromJust)
 import Data.Maybe (fromJust)
-import LinkedIn.UIElements.Parser (toYear)
-import LinkedIn.UIElements.Types (MonthYear(..))
+import LinkedIn.UI.Basic.Parser (toYear)
+import LinkedIn.UI.Basic.Types (MonthYear(..))
 import Partial.Unsafe (unsafePartial)
 import Partial.Unsafe (unsafePartial)
 
 
 toMonthYear' :: Month -> Int -> MonthYear
 toMonthYear' :: Month -> Int -> MonthYear