{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

-- |
-- Module      : Language.Github.Actions.Step.Id
-- Description : Step identifiers for GitHub Actions workflows
-- Copyright   : (c) 2025 Bellroy Pty Ltd
-- License     : BSD-3-Clause
-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
--
-- This module provides the 'StepId' type for uniquely identifying steps within
-- GitHub Actions jobs.
--
-- Step IDs are used to reference step outputs from later steps in the same job
-- or from other jobs. They must be unique within a job and follow specific
-- naming conventions.
--
-- For more information about GitHub Actions step IDs, see:
-- <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsid>
module Language.Github.Actions.Step.Id
  ( StepId (..),
    gen,
    render,
  )
where

import Data.Aeson (FromJSON, FromJSONKey, ToJSON (..), ToJSONKey)
import Data.Text (Text)
import GHC.Generics (Generic)
import Hedgehog (MonadGen)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

-- | A unique identifier for a step within a GitHub Actions job.
--
-- Step IDs are used to:
-- * Reference step outputs from later steps using @steps.<step_id>.outputs.<output_name>@
-- * Reference step outcomes using @steps.<step_id>.outcome@ or @steps.<step_id>.conclusion@
-- * Create dependencies between steps (though steps run sequentially by default)
--
-- Step IDs must be unique within a job and should follow these conventions:
-- * Start with a letter or underscore
-- * Contain only alphanumeric characters, hyphens, and underscores
-- * Be descriptive of the step's purpose
--
-- Example usage:
--
-- @
-- import Language.Github.Actions.Step.Id
--
-- -- Simple step IDs
-- checkoutStepId :: StepId
-- checkoutStepId = StepId "checkout"
--
-- buildStepId :: StepId
-- buildStepId = StepId "build"
--
-- -- More descriptive step IDs
-- uploadArtifactsStepId :: StepId
-- uploadArtifactsStepId = StepId "upload-build-artifacts"
-- @
--
-- For more details, see: <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsid>
newtype StepId = StepId Text
  deriving stock (StepId -> StepId -> Bool
(StepId -> StepId -> Bool)
-> (StepId -> StepId -> Bool) -> Eq StepId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StepId -> StepId -> Bool
== :: StepId -> StepId -> Bool
$c/= :: StepId -> StepId -> Bool
/= :: StepId -> StepId -> Bool
Eq, (forall x. StepId -> Rep StepId x)
-> (forall x. Rep StepId x -> StepId) -> Generic StepId
forall x. Rep StepId x -> StepId
forall x. StepId -> Rep StepId x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. StepId -> Rep StepId x
from :: forall x. StepId -> Rep StepId x
$cto :: forall x. Rep StepId x -> StepId
to :: forall x. Rep StepId x -> StepId
Generic, Eq StepId
Eq StepId =>
(StepId -> StepId -> Ordering)
-> (StepId -> StepId -> Bool)
-> (StepId -> StepId -> Bool)
-> (StepId -> StepId -> Bool)
-> (StepId -> StepId -> Bool)
-> (StepId -> StepId -> StepId)
-> (StepId -> StepId -> StepId)
-> Ord StepId
StepId -> StepId -> Bool
StepId -> StepId -> Ordering
StepId -> StepId -> StepId
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: StepId -> StepId -> Ordering
compare :: StepId -> StepId -> Ordering
$c< :: StepId -> StepId -> Bool
< :: StepId -> StepId -> Bool
$c<= :: StepId -> StepId -> Bool
<= :: StepId -> StepId -> Bool
$c> :: StepId -> StepId -> Bool
> :: StepId -> StepId -> Bool
$c>= :: StepId -> StepId -> Bool
>= :: StepId -> StepId -> Bool
$cmax :: StepId -> StepId -> StepId
max :: StepId -> StepId -> StepId
$cmin :: StepId -> StepId -> StepId
min :: StepId -> StepId -> StepId
Ord, Int -> StepId -> ShowS
[StepId] -> ShowS
StepId -> String
(Int -> StepId -> ShowS)
-> (StepId -> String) -> ([StepId] -> ShowS) -> Show StepId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StepId -> ShowS
showsPrec :: Int -> StepId -> ShowS
$cshow :: StepId -> String
show :: StepId -> String
$cshowList :: [StepId] -> ShowS
showList :: [StepId] -> ShowS
Show)
  deriving newtype (Maybe StepId
Value -> Parser [StepId]
Value -> Parser StepId
(Value -> Parser StepId)
-> (Value -> Parser [StepId]) -> Maybe StepId -> FromJSON StepId
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: Value -> Parser StepId
parseJSON :: Value -> Parser StepId
$cparseJSONList :: Value -> Parser [StepId]
parseJSONList :: Value -> Parser [StepId]
$comittedField :: Maybe StepId
omittedField :: Maybe StepId
FromJSON, FromJSONKeyFunction [StepId]
FromJSONKeyFunction StepId
FromJSONKeyFunction StepId
-> FromJSONKeyFunction [StepId] -> FromJSONKey StepId
forall a.
FromJSONKeyFunction a -> FromJSONKeyFunction [a] -> FromJSONKey a
$cfromJSONKey :: FromJSONKeyFunction StepId
fromJSONKey :: FromJSONKeyFunction StepId
$cfromJSONKeyList :: FromJSONKeyFunction [StepId]
fromJSONKeyList :: FromJSONKeyFunction [StepId]
FromJSONKey, [StepId] -> Value
[StepId] -> Encoding
StepId -> Bool
StepId -> Value
StepId -> Encoding
(StepId -> Value)
-> (StepId -> Encoding)
-> ([StepId] -> Value)
-> ([StepId] -> Encoding)
-> (StepId -> Bool)
-> ToJSON StepId
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: StepId -> Value
toJSON :: StepId -> Value
$ctoEncoding :: StepId -> Encoding
toEncoding :: StepId -> Encoding
$ctoJSONList :: [StepId] -> Value
toJSONList :: [StepId] -> Value
$ctoEncodingList :: [StepId] -> Encoding
toEncodingList :: [StepId] -> Encoding
$comitField :: StepId -> Bool
omitField :: StepId -> Bool
ToJSON, ToJSONKeyFunction [StepId]
ToJSONKeyFunction StepId
ToJSONKeyFunction StepId
-> ToJSONKeyFunction [StepId] -> ToJSONKey StepId
forall a.
ToJSONKeyFunction a -> ToJSONKeyFunction [a] -> ToJSONKey a
$ctoJSONKey :: ToJSONKeyFunction StepId
toJSONKey :: ToJSONKeyFunction StepId
$ctoJSONKeyList :: ToJSONKeyFunction [StepId]
toJSONKeyList :: ToJSONKeyFunction [StepId]
ToJSONKey)

gen :: (MonadGen m) => m StepId
gen :: forall (m :: * -> *). MonadGen m => m StepId
gen = Text -> StepId
StepId (Text -> StepId) -> m Text -> m StepId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Range Int -> m Char -> m Text
forall (m :: * -> *). MonadGen m => Range Int -> m Char -> m Text
Gen.text (Int -> Int -> Range Int
forall a. Integral a => a -> a -> Range a
Range.linear Int
1 Int
5) m Char
forall (m :: * -> *). MonadGen m => m Char
Gen.alphaNum

render :: StepId -> Text
render :: StepId -> Text
render (StepId Text
t) = Text
t