{{/* Hugo Blox: Dynamic Tailwind @source generation for Hugo modules */}}
{{/* Documentation: https://hugoblox.com/docs/ */}}
{{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}}

{{/*
This partial generates Tailwind CSS @source directives that tell Tailwind where to scan for CSS classes.

It provides a robust bridge between Hugo's virtual filesystem (which includes module mounts)
and Tailwind's real filesystem scanner.
*/}}
{{ $paths := slice }}

{{/* 1. Always scan the site's source files. */}}
{{ $paths = $paths | append `content/**/*.md` }}
{{ $paths = $paths | append `layouts/**/*.html` }}
{{ $paths = $paths | append `assets/js/**/*.js` }}
{{ $paths = $paths | append `assets/js/**/*.jsx` }}
{{ $paths = $paths | append `assets/js/**/*.tsx` }}
{{ $paths = $paths | append `hugo_stats.json` }}

{{/*
2.  Crucially, scan Hugo's generated JS output from Preact components.
    These files are built by Hugo's `js.Build` into a predictable location within the
    project's `assets` directory, making them a reliable source for Tailwind to scan.
    This step happens before Tailwind runs, thanks to `templates.Defer` in `site_head.html`.
*/}}
{{ $paths = $paths | append `assets/js/preact-built/**/*.js` }}

{{/*
3. Comprehensive class extraction from Preact JSX/TSX source files.

   Hugo's virtual filesystem mounts block JSX/TSX into assets/js/hbx/blocks/.
   Tailwind's @source file paths only work on the real filesystem, but these
   files exist only in Hugo's virtual FS (or in a module cache for remote modules).
   So we read the file content via resources.Match and extract class candidates inline.

   Strategy: Extract ALL string literal content — not just class= attributes.
   This catches classes in any pattern:
     - Static attrs:     class="gap-8 items-center"
     - JSX expressions:  class={"gap-8 items-center"}
     - Template literals: class={`gap-8 ${cond ? "md:grid" : ""}`}
     - Utility fns:      cn("gap-8", condition && "md:grid-cols-2")

   Tailwind's scanner automatically ignores non-class tokens (import paths,
   error messages, etc.), so false positives are harmless.
*/}}
{{ $all_jsx := resources.Match "js/hbx/**/*.jsx" }}
{{ $all_tsx := resources.Match "js/hbx/**/*.tsx" }}

{{ $extracted_classes := slice }}
{{ range $f := $all_jsx | append $all_tsx }}
  {{ $code := $f.Content }}

  {{/* A) Extract content of all double-quoted strings */}}
  {{ $dq_matches := findRE `"[^"]*"` $code }}
  {{ range $m := $dq_matches }}
    {{ $str := strings.TrimPrefix `"` (strings.TrimSuffix `"` $m) }}
    {{ range split $str " " }}
      {{ $t := strings.TrimSpace . }}
      {{/* Filter out tokens with unsafe characters (braces, quotes, parens) */}}
      {{ if and $t (not (findRE `[\{\}\(\)"';]` $t)) }}
        {{ $extracted_classes = $extracted_classes | append $t }}
      {{ end }}
    {{ end }}
  {{ end }}

  {{/* B) Extract static parts of template literals (backtick strings) */}}
  {{/* Removes ${...} interpolations, keeping surrounding text */}}
  {{ $bt_matches := findRE "`[^`]*`" $code }}
  {{ range $m := $bt_matches }}
    {{ $str := strings.TrimPrefix "`" (strings.TrimSuffix "`" $m) }}
    {{ $static := replaceRE `\$\{[^}]*\}` " " $str }}
    {{ range split $static " " }}
      {{ $t := strings.TrimSpace . }}
      {{/* Filter out tokens with unsafe characters (braces, quotes, parens) */}}
      {{ if and $t (not (findRE `[\{\}\(\)"';]` $t)) }}
        {{ $extracted_classes = $extracted_classes | append $t }}
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

{{ $extracted_classes = $extracted_classes | uniq }}
{{ range $class := $extracted_classes }}
@source inline("{{ $class }}");
{{ end }}

{{/* Generate the @source rules */}}
{{ range $paths }}
@source "{{ . }}";
{{ end }}