quillmark-typst 0.55.0

Typst backend for Quillmark
Documentation
// Auto-generated quillmark-helper package
// Version: {version}

/// Parse an ISO 8601 date string (YYYY-MM-DD) to a Typst datetime
/// Handles both pure dates (2024-01-15) and datetime strings (2024-01-15T10:30:00)
/// Must be defined before `data` — Typst does not hoist `#let` bindings.
#let _parse-date(s) = {
  if s == none { return none }
  let date-str = str(s)
  // Handle datetime strings by extracting just the date part
  if date-str.contains("T") {
    date-str = date-str.split("T").at(0)
  }
  let parts = date-str.split("-")
  if parts.len() < 3 { return none }
  let year = int(parts.at(0))
  let month = int(parts.at(1))
  // Take only the first 2 characters in case there's extra content
  let day-str = parts.at(2)
  if day-str.len() > 2 { day-str = day-str.slice(0, 2) }
  let day = int(day-str)
  datetime(year: year, month: month, day: day)
}

/// Document data as a dictionary.
/// Markdown fields are automatically converted to Typst content objects.
/// The `__meta__` key (injected by the Rust backend) is consumed here and
/// never exposed to plate authors.
#let data = {
  let d = json(bytes("{escaped_json}"))

  // Read and consume __meta__ (injected by transform_fields)
  let meta = d.remove("__meta__", default: (
    content_fields: (),
    card_content_fields: (:),
    date_fields: (),
    card_date_fields: (:),
  ))

  // Auto-eval top-level content fields
  for key in meta.content_fields {
    if key in d {
      let val = d.at(key)
      if type(val) == str and val != "" {
        d.insert(key, eval(val, mode: "markup"))
      }
    }
  }

  // Auto-convert top-level date fields to datetime
  for key in meta.date_fields {
    if key in d {
      let val = d.at(key)
      if val != none {
        d.insert(key, _parse-date(val))
      }
    }
  }

  // Auto-eval content fields within each CARD
  if "CARDS" in d {
    let cards = ()
    for card in d.at("CARDS") {
      let card-type = card.at("CARD", default: none)
      let fields = meta.card_content_fields.at(card-type, default: ())
      for key in fields {
        if key in card {
          let val = card.at(key)
          if type(val) == str and val != "" {
            card.insert(key, eval(val, mode: "markup"))
          }
        }
      }

      // Auto-convert date fields for this card type
      let date-fields = meta.card_date_fields.at(card-type, default: ())
      for key in date-fields {
        if key in card {
          let val = card.at(key)
          if val != none {
            card.insert(key, _parse-date(val))
          }
        }
      }

      cards.push(card)
    }
    d.insert("CARDS", cards)
  }

  d
}