packages feed

gachi-scaffold-0.1.0.0: src/Gachi/Scaffold/Types.hs

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

-- | Module: Gachi.Scaffold.Types
-- Description: Core types and configuration models for workspace scaffolding
--
-- This module establishes the structural types and configuration options
-- governing project scaffolding, file generation, error handling, and
-- filesystem materialization.
--
-- = Architectural Context & Invariants
--
-- In Gachi's infrastructure model (per Note [Ecosystem Standardization Invariants]
-- [ref:note-ecosystem-standardization]), all repository skeletons are materialized
-- from an immutable, deterministic list of 'FileEntry' records.
--
-- == Two-Phase Scaffolding Architecture
--
-- Generation proceeds in two strictly decoupled phases:
--
-- 1. __Pure Synthesis (Phase A):__
--    The template engine transforms a declarative 'Gachi.Schema.Project.Project'
--    specification into an in-memory list of 'FileEntry' values. This phase is
--    referentially transparent, pure, and total, with zero filesystem or network
--    side-effects.
--
-- 2. __Materialization (Phase B):__
--    The execution engine writes the in-memory 'FileEntry' list to the physical
--    filesystem according to the active 'ScaffoldMode', creating directories as
--    needed and setting POSIX executable bits (+x) for shell and Python scripts.
--
-- = When to Use This Module
--
-- Import this module when configuring scaffolding executions, processing
-- in-memory generated files, or handling scaffolding results and errors.
module Gachi.Scaffold.Types
  ( -- * Core File Representation
    FileEntry(..)

    -- * Operational Modes
  , ScaffoldMode(..)

    -- * Results and Errors
  , ScaffoldResult(..)
  , ScaffoldError(..)
  ) where

import Control.Exception (Exception)
import Data.Text (Text)
import GHC.Generics (Generic)

-- | Represents a single file to be generated or materialized in a project skeleton.
--
-- Each 'FileEntry' holds a relative path, textual content, and a flag indicating
-- whether the file requires POSIX executable permissions (such as verification scripts
-- in @bin/@ or Git hooks in @.githooks/@).
data FileEntry = FileEntry
  { entryPath       :: !FilePath
    -- ^ Relative file path from the repository root (e.g. @"docs/INDEX.md"@).
  , entryContent    :: !Text
    -- ^ Complete textual content of the file to be written.
  , entryExecutable :: !Bool
    -- ^ Whether POSIX executable permissions (@+x@) must be applied upon creation.
  } deriving stock (Eq, Show, Generic)

-- | Operational policy governing how the scaffolding engine behaves when a
-- target file already exists on the destination filesystem.
--
-- Used to differentiate between initial repository creation, non-destructive
-- retrofitting, and dry-run synchronization.
data ScaffoldMode
  = OverwriteExisting
    -- ^ Overwrite any existing files unconditionally.
  | SkipExisting
    -- ^ Preserve existing files intact, recording them as skipped in 'ScaffoldResult'.
  | FailOnExisting
    -- ^ Abort immediately with a 'DestinationExists' error if any file already exists.
  deriving stock (Eq, Show, Generic)

-- | Summary outcome of a completed scaffolding operation across a filesystem tree.
--
-- Tracks both newly written files and skipped files to provide transparent
-- diagnostic reporting to CLI users and calling code.
data ScaffoldResult = ScaffoldResult
  { writtenFiles :: ![FilePath]
    -- ^ List of file paths successfully materialized on disk.
  , skippedFiles :: ![FilePath]
    -- ^ List of file paths preserved untouched because they already existed.
  } deriving stock (Eq, Show, Generic)

-- | Scaffolding execution errors encountered during filesystem materialization.
--
-- Instances of 'Exception' allowing safe capture and propagation via 'Control.Exception.throwIO'.
data ScaffoldError
  = DestinationExists !FilePath
    -- ^ A destination file already exists and 'ScaffoldMode' was set to 'FailOnExisting'.
  | FileWriteFailure !FilePath !String
    -- ^ An unhandled I/O error occurred while writing to disk.
  deriving stock (Eq, Show, Generic)

instance Exception ScaffoldError