smith.domain.value_objects

Domain value objects — immutable data structures used across the domain.

 1"""Domain value objects — immutable data structures used across the domain."""
 2
 3from dataclasses import dataclass
 4from enum import Enum
 5from pathlib import Path
 6from typing import Literal
 7
 8
 9@dataclass(frozen=True)
10class FileSpec:
11    """A template file's relative path and binary content."""
12
13    relative_path: Path
14    content: bytes
15
16
17@dataclass(frozen=True)
18class TemplateSource:
19    """Identifies where a template originates (bundled, local, or URL)."""
20
21    kind: Literal["bundled", "local", "url"]
22    location: str
23
24
25class ConnectionState(Enum):
26    """Possible states of a project's connection to a template source."""
27
28    CONNECTED = "connected"
29    DISCONNECTED = "disconnected"
30    PARTIAL = "partial"
31
32
33@dataclass(frozen=True)
34class ConnectionStatus:
35    """Snapshot of a project's connection state and file presence."""
36
37    state: ConnectionState
38    source: TemplateSource | None
39    present_files: list[Path]
40    missing_files: list[Path]
41
42    def to_dict(self) -> dict:
43        """Serialise the status to a plain dictionary."""
44        return {
45            "state": self.state.value,
46            "source": (
47                {"kind": self.source.kind, "location": self.source.location}
48                if self.source
49                else None
50            ),
51            "present_files": [str(p) for p in self.present_files],
52            "missing_files": [str(p) for p in self.missing_files],
53        }
54
55
56@dataclass(frozen=True)
57class GitignoreSection:
58    """A delimited block of patterns inside .gitignore managed by smith."""
59
60    patterns: list[str]
61    start_marker: str = "# smith managed"
62    end_marker: str = "# end smith managed"
@dataclass(frozen=True)
class FileSpec:
10@dataclass(frozen=True)
11class FileSpec:
12    """A template file's relative path and binary content."""
13
14    relative_path: Path
15    content: bytes

A template file's relative path and binary content.

FileSpec(relative_path: pathlib._local.Path, content: bytes)
relative_path: pathlib._local.Path
content: bytes
@dataclass(frozen=True)
class TemplateSource:
18@dataclass(frozen=True)
19class TemplateSource:
20    """Identifies where a template originates (bundled, local, or URL)."""
21
22    kind: Literal["bundled", "local", "url"]
23    location: str

Identifies where a template originates (bundled, local, or URL).

TemplateSource(kind: Literal['bundled', 'local', 'url'], location: str)
kind: Literal['bundled', 'local', 'url']
location: str
class ConnectionState(enum.Enum):
26class ConnectionState(Enum):
27    """Possible states of a project's connection to a template source."""
28
29    CONNECTED = "connected"
30    DISCONNECTED = "disconnected"
31    PARTIAL = "partial"

Possible states of a project's connection to a template source.

CONNECTED = <ConnectionState.CONNECTED: 'connected'>
DISCONNECTED = <ConnectionState.DISCONNECTED: 'disconnected'>
PARTIAL = <ConnectionState.PARTIAL: 'partial'>
@dataclass(frozen=True)
class ConnectionStatus:
34@dataclass(frozen=True)
35class ConnectionStatus:
36    """Snapshot of a project's connection state and file presence."""
37
38    state: ConnectionState
39    source: TemplateSource | None
40    present_files: list[Path]
41    missing_files: list[Path]
42
43    def to_dict(self) -> dict:
44        """Serialise the status to a plain dictionary."""
45        return {
46            "state": self.state.value,
47            "source": (
48                {"kind": self.source.kind, "location": self.source.location}
49                if self.source
50                else None
51            ),
52            "present_files": [str(p) for p in self.present_files],
53            "missing_files": [str(p) for p in self.missing_files],
54        }

Snapshot of a project's connection state and file presence.

ConnectionStatus( state: ConnectionState, source: TemplateSource | None, present_files: list[pathlib._local.Path], missing_files: list[pathlib._local.Path])
source: TemplateSource | None
present_files: list[pathlib._local.Path]
missing_files: list[pathlib._local.Path]
def to_dict(self) -> dict:
43    def to_dict(self) -> dict:
44        """Serialise the status to a plain dictionary."""
45        return {
46            "state": self.state.value,
47            "source": (
48                {"kind": self.source.kind, "location": self.source.location}
49                if self.source
50                else None
51            ),
52            "present_files": [str(p) for p in self.present_files],
53            "missing_files": [str(p) for p in self.missing_files],
54        }

Serialise the status to a plain dictionary.

@dataclass(frozen=True)
class GitignoreSection:
57@dataclass(frozen=True)
58class GitignoreSection:
59    """A delimited block of patterns inside .gitignore managed by smith."""
60
61    patterns: list[str]
62    start_marker: str = "# smith managed"
63    end_marker: str = "# end smith managed"

A delimited block of patterns inside .gitignore managed by smith.

GitignoreSection( patterns: list[str], start_marker: str = '# smith managed', end_marker: str = '# end smith managed')
patterns: list[str]
start_marker: str = '# smith managed'
end_marker: str = '# end smith managed'