pyssg is pre-1.0 and under active development - APIs, config, and themes may change.
pyssg.core.incremental.hashing

1 min read

pyssg.core.incremental.hashing

Aspect hashing & node identity.

Each node hashes its facets independently (raw, frontmatter, body, content_html, ...). Hashing is blake2b over newline-normalized bytes so a \r\n vs \n difference never spuriously invalidates. Everything here is deterministic and stdlib-only.

canonical_bytes(value: object) -> bytes

Deterministic byte encoding of a value for hashing.

bytes/str pass through (str newline-normalized); everything else goes through canonical JSON (sorted keys, compact) so dict/list ordering can never change the digest.

compute_raw_hash(data: bytes) -> Digest

Hash raw file bytes with newline normalization.

digest(*parts: object) -> Digest

Combine several values into one digest (used for composite cache keys).

hash_aspect(node: Node, aspect: Aspect, value: object) -> Digest

Compute, store and return the digest of one aspect of node.

resolve_identity(path: str, fm: Mapping[str, object], raw_hash: Digest, recently_deleted: dict[Digest, NodeId]) -> NodeId

Resolve the stable logical NodeId for a file.

Order: frontmatter id -> move-detect (raw hash of a just-deleted node) -> slug -> path fallback. This is what keeps backlinks intact across renames.