Class: Markawesome::DateTransformer

Inherits:
BaseTransformer show all
Defined in:
lib/markawesome/transformers/date_transformer.rb

Overview

Transforms declarative timestamp syntax into Web Awesome’s two timestamp components:

<wa-format-date>   — an absolute, locale-formatted date ("June 26, 2026")
<wa-relative-time> — a relative phrase ("3 days ago"), optionally ticking

These are pure declarative wrappers over the browser’s Intl.DateTimeFormat / Intl.RelativeTimeFormat: the date value is baked into the markup at build time, with no data fetching. Great for blog dates, changelog stamps, and “last updated”.

Inline (primary): [[[ <date> <tokens> ]]] Block (alternative): :::wa-format-date <date> <tokens> / :::wa-relative-time …

followed by a closing ::: (empty body)

Mode: absolute (<wa-format-date>) is the default; a bare ‘relative` token in the inline form switches to <wa-relative-time>. The block selector name chooses the mode directly.

Static-site caveat: both components render generated text into shadow DOM with no light-DOM fallback — with Web Awesome’s JS disabled they show nothing. This is identical to <wa-icon> and the other generated-content components we already emit, so it is consistent with our model.

Constant Summary collapse

INLINE_REGEX =

Inline: content excludes ‘]`, non-greedy, multiple-per-line, single-line.

/\[\[\[[ \t]*([^\]\r\n]+?)[ \t]*\]\]\]/
ALTERNATIVE_REGEX =

Block: selector name picks the mode; an empty body, closed by ‘:::`.

/^:::wa-(format-date|relative-time)[ \t]*([^\n]*)\n:::$/
DATE_TOKEN_REGEX =

A token is the date when it is an ISO 8601 date or datetime (datetimes use the ‘T` separator — a space would break whitespace tokenization).

/\A\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)?\z/
STYLE_PRESETS =

style:/time: presets expand to Web Awesome’s granular date/time attributes.

{
  'short' => { 'month' => 'numeric', 'day' => 'numeric', 'year' => '2-digit' },
  'medium' => { 'month' => 'short', 'day' => 'numeric', 'year' => 'numeric' },
  'long' => { 'month' => 'long', 'day' => 'numeric', 'year' => 'numeric' },
  'full' => { 'weekday' => 'long', 'month' => 'long', 'day' => 'numeric', 'year' => 'numeric' }
}.freeze
TIME_PRESETS =
{
  'short' => { 'hour' => 'numeric', 'minute' => 'numeric' },
  'medium' => { 'hour' => 'numeric', 'minute' => 'numeric', 'second' => 'numeric' },
  'long' => { 'hour' => 'numeric', 'minute' => 'numeric', 'second' => 'numeric', 'time-zone-name' => 'short' },
  'full' => { 'hour' => 'numeric', 'minute' => 'numeric', 'second' => 'numeric', 'time-zone-name' => 'long' }
}.freeze
GRANULAR_ENUMS =

Granular key:value tokens that pass through to the same-named WA attribute, validated against an allowed enum (invalid values dropped).

{
  'weekday' => %w[narrow short long],
  'era' => %w[narrow short long],
  'year' => %w[numeric 2-digit],
  'month' => %w[numeric 2-digit narrow short long],
  'day' => %w[numeric 2-digit],
  'hour' => %w[numeric 2-digit],
  'minute' => %w[numeric 2-digit],
  'second' => %w[numeric 2-digit],
  'hour-format' => %w[auto 12 24],
  'time-zone-name' => %w[short long]
}.freeze
CONTENT_FIELDS =

Granular keys that count as an explicit date/time field — their presence (or a style:/time: preset) suppresses the style:long default.

%w[weekday era year month day hour minute second time-zone-name].freeze
FORMAT_DATE_ORDER =

Deterministic emission order (required for byte-for-byte parity).

%w[date weekday era year month day hour minute second
time-zone-name time-zone hour-format lang].freeze
RELATIVE_FORMATS =
%w[long short narrow].freeze
RELATIVE_NUMERICS =
%w[auto always].freeze

Class Method Summary collapse

Class Method Details

.render_as_markdown(content, _options = {}) ⇒ Object

Plain-markdown degradation: there is no locale formatting in plain text, so each timestamp degrades to its raw date string (empty when omitted).



91
92
93
94
95
96
97
# File 'lib/markawesome/transformers/date_transformer.rb', line 91

def self.render_as_markdown(content, _options = {})
  patterns = [
    { regex: INLINE_REGEX, block: proc { |_m, md| extract_date(md[1]) } },
    { regex: ALTERNATIVE_REGEX, block: proc { |_m, md| extract_date(md[2]) } }
  ]
  apply_multiple_patterns(content, patterns)
end

.transform(content) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/markawesome/transformers/date_transformer.rb', line 80

def self.transform(content)
  patterns = [
    { regex: INLINE_REGEX, block: proc { |_m, md| render_tokens(md[1], nil) } },
    { regex: ALTERNATIVE_REGEX,
      block: proc { |_m, md| render_tokens(md[2], md[1] == 'relative-time' ? :relative : :absolute) } }
  ]
  apply_multiple_patterns(content, patterns)
end