computeFrontmatterHashTextBasedWithReader computes the hash using text-based approach with custom file reader. When markdown is non-empty, it is included as the full body text in the canonical data (used for inlined-imports mode where the entire body is compiled into the lock file).
(frontmatterText, markdown, baseDir string, cache *ImportCache, expressions []string, fileReader FileReader)
| 577 | // When markdown is non-empty, it is included as the full body text in the canonical data (used for |
| 578 | // inlined-imports mode where the entire body is compiled into the lock file). |
| 579 | func computeFrontmatterHashTextBasedWithReader(frontmatterText, markdown, baseDir string, cache *ImportCache, expressions []string, fileReader FileReader) (string, error) { |
| 580 | frontmatterHashLog.Print("Computing frontmatter hash using text-based approach") |
| 581 | |
| 582 | // Process imports using text-based parsing with custom file reader |
| 583 | visited := make(map[string]struct { |
| 584 | }) |
| 585 | importedFiles, importedFrontmatterTexts, err := processImportsTextBased(frontmatterText, baseDir, visited, fileReader) |
| 586 | if err != nil { |
| 587 | return "", fmt.Errorf("failed to process imports: %w", err) |
| 588 | } |
| 589 | |
| 590 | // Build canonical representation from text |
| 591 | canonical := make(map[string]any) |
| 592 | |
| 593 | normalizedFrontmatterText := normalizeFrontmatterText(frontmatterText) |
| 594 | normalizedImportedTexts := make([]string, len(importedFrontmatterTexts)) |
| 595 | for i, text := range importedFrontmatterTexts { |
| 596 | normalizedImportedTexts[i] = normalizeFrontmatterText(text) |
| 597 | } |
| 598 | |
| 599 | if err := validateFrontmatterHashInputSize(normalizedFrontmatterText, normalizedImportedTexts); err != nil { |
| 600 | return "", err |
| 601 | } |
| 602 | |
| 603 | // Add the main frontmatter text as-is (trimmed and normalized) |
| 604 | canonical["frontmatter-text"] = normalizedFrontmatterText |
| 605 | |
| 606 | // Add sorted imported files list |
| 607 | if len(importedFiles) > 0 { |
| 608 | sort.Strings(importedFiles) |
| 609 | canonical["imports"] = importedFiles |
| 610 | } |
| 611 | |
| 612 | // Add sorted imported frontmatter texts (concatenated with delimiter) |
| 613 | if len(normalizedImportedTexts) > 0 { |
| 614 | sort.Strings(normalizedImportedTexts) |
| 615 | canonical["imported-frontmatters"] = strings.Join(normalizedImportedTexts, "\n---\n") |
| 616 | } |
| 617 | |
| 618 | // When inlined-imports is enabled, include the full markdown body so any content |
| 619 | // change invalidates the hash. Otherwise, include only relevant template expressions. |
| 620 | if markdown != "" { |
| 621 | canonical["body-text"] = markdown |
| 622 | } else if len(expressions) > 0 { |
| 623 | canonical["template-expressions"] = expressions |
| 624 | } |
| 625 | |
| 626 | // Serialize to canonical JSON |
| 627 | canonicalJSON := marshalSorted(canonical) |
| 628 | |
| 629 | frontmatterHashLog.Printf("Canonical JSON length: %d bytes", len(canonicalJSON)) |
| 630 | |
| 631 | // Compute SHA-256 hash |
| 632 | hash := sha256.Sum256([]byte(canonicalJSON)) |
| 633 | hashHex := hex.EncodeToString(hash[:]) |
| 634 | |
| 635 | frontmatterHashLog.Printf("Computed hash: %s", hashHex) |
| 636 | return hashHex, nil |
no test coverage detected