barefoot_js 0.25.0 → 0.30.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/barefoot_js.rb +106 -13
  3. metadata +31 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01c03141b87505bcc2834d5acbf460b92def83f0932ab62845fcfdc4ea1a5b45
4
- data.tar.gz: f51524718fa1c54848ffe68bdbf1ea7f48ef899a5eaaf879ec47ae5ffc436ff4
3
+ metadata.gz: ca797efa51cecb1fa7eb049f0689fa0fff77996e0d97ccee9102639c359f13f7
4
+ data.tar.gz: eba717d9c886f1569ce5882a9ef43b5ebcf5a444da4dcd050f51e6a3009cad45
5
5
  SHA512:
6
- metadata.gz: 92165ba796d909d7995b962a3074f537d7709344817abdb78eb1818c76bcec761fcb6d033d7c4660e26bc624dcf91c85978455c7cdcf85e7231ccd43478ae514
7
- data.tar.gz: 97beda0b52738f73a9b25b3910ce2a6e0eb3c8b274c7613a2ec332147114dcb4c72133310ee5cff89a0f86caa46d63940afae249148323e5b66238044d74dfb7
6
+ metadata.gz: 4cc5ee0e33f116f6142cc85a41be5f28b62ccdfaa07781570f8db776f6bb438e158ecad23dd56366ea0764625d31bdaef0a0918d9cbd6f803f4277ff1fbbb9a5
7
+ data.tar.gz: 85d238ab63966d116da0ba390b990ae2088a3010d6a866f0a06302b159af3ba46fa1d04012ce2c4b836649384a75504ad2d91edca99df18f2682825df2ebf63b
data/lib/barefoot_js.rb CHANGED
@@ -530,9 +530,12 @@ module BarefootJS
530
530
  end
531
531
 
532
532
  # `tz` shapes FORMAT_DATE_OFFSET_RE matches: a fixed UTC offset `±HH:MM`
533
- # (`'+09:00'`, `'-05:30'`) -- the ONLY non-UTC shape `format_date`
534
- # recognizes (mirrors OFFSET_RE in packages/client/src/format-date.ts).
535
- FORMAT_DATE_OFFSET_RE = /\A([+-])(\d{2}):(\d{2})\z/
533
+ # within ECMA-402's valid range -- hours 00-23, minutes 00-59
534
+ # (`'+09:00'`, `'-05:30'`) -- one of the three `tz` shapes `format_date`
535
+ # accepts (mirrors OFFSET_RE in packages/client/src/format-date.ts). An
536
+ # out-of-range shape (`'+25:00'`) falls through to the tzdata lookup,
537
+ # fails it, and raises -- matching the JS reference's RangeError (#2344).
538
+ FORMAT_DATE_OFFSET_RE = /\A([+-])([01]\d|2[0-3]):([0-5]\d)\z/
536
539
 
537
540
  # Longest-match pattern-token alternation (mirrors TOKEN_RE in
538
541
  # packages/client/src/format-date.ts). Order matters: Onigmo, like JS's
@@ -562,13 +565,20 @@ module BarefootJS
562
565
  # an ISO-8601 string, normalized identically. A nil / unparseable
563
566
  # receiver renders '' (never raises mid-render).
564
567
  #
565
- # tz: a fixed UTC offset `±HH:MM` shifts the instant by
566
- # sign*(HH*60+MM) minutes; ANY other value -- 'UTC', an IANA zone name
567
- # ('Asia/Tokyo'), or a malformed offset ('+9:00') -- normalizes to a
568
- # zero-minute shift (UTC), so every backend degrades identically instead
569
- # of dragging in host tzdata. The shifted instant's UTC calendar fields
570
- # (not the original instant's) are what pattern tokens read -- the
571
- # shifted UTC clock face IS the local clock face at that offset. `Time`
568
+ # tz (#2344): 'UTC', a range-valid fixed offset `±HH:MM` (shifts the
569
+ # instant by sign*(HH*60+MM) minutes), or a canonical IANA zone name
570
+ # ('Asia/Tokyo') resolved through tzdata via the tzinfo gem -- the
571
+ # zone's UTC offset AT THE INSTANT being formatted (DST-aware,
572
+ # historical-transition-aware, seconds precision: pre-standard LMT
573
+ # offsets like Tokyo's +09:18:59 count). ANY other value -- an unknown
574
+ # zone, a non-canonical spelling, a malformed or out-of-range offset
575
+ # ('+9:00', '+25:00') -- raises ArgumentError, aborting the render
576
+ # loudly: the JS reference throws a RangeError there, and a silently
577
+ # substituted timezone is the one failure mode this helper must not
578
+ # have (the pre-#2344 normalize-to-UTC total function is gone). The
579
+ # shifted instant's UTC calendar fields (not the original instant's)
580
+ # are what pattern tokens read -- the shifted UTC clock face IS the
581
+ # local clock face in that zone. `Time`
572
582
  # arithmetic here is exact (Ruby represents the instant as a Rational,
573
583
  # not a floor-divided epoch-millis integer), so there's no pre-1970
574
584
  # negative-epoch floor-division trap to dodge the way a naive
@@ -602,10 +612,19 @@ module BarefootJS
602
612
  end
603
613
  return '' if t.nil?
604
614
 
605
- m = FORMAT_DATE_OFFSET_RE.match(tz.to_s)
606
- offset_minutes = m ? (m[1] == '-' ? -1 : 1) * ((m[2].to_i * 60) + m[3].to_i) : 0
615
+ tz_s = tz.to_s
616
+ offset_seconds = 0
617
+ if tz_s != 'UTC'
618
+ m = FORMAT_DATE_OFFSET_RE.match(tz_s)
619
+ offset_seconds =
620
+ if m
621
+ (m[1] == '-' ? -1 : 1) * ((m[2].to_i * 60) + m[3].to_i) * 60
622
+ else
623
+ format_date_zone_offset(tz_s, t)
624
+ end
625
+ end
607
626
 
608
- shifted = (t.utc + (offset_minutes * 60)).utc
627
+ shifted = (t.utc + offset_seconds).utc
609
628
  year = shifted.year
610
629
  month = shifted.mon
611
630
  day = shifted.mday
@@ -628,6 +647,29 @@ module BarefootJS
628
647
  end
629
648
  end
630
649
 
650
+ # Resolve a canonical IANA zone ID's UTC offset (whole seconds) at
651
+ # instant `t` through the tzinfo gem (#2344) -- TZInfo resolves the
652
+ # exact-case canonical ID set every backend shares, with full
653
+ # historical transitions (LMT seconds included). The gem is required
654
+ # lazily so the fixed-offset/'UTC' paths -- and every other helper --
655
+ # keep working on a gem-less stdlib install; reaching a named zone
656
+ # without the gem raises the same loud ArgumentError as an unknown
657
+ # zone (never a silent UTC fallback).
658
+ def format_date_zone_offset(tz, t)
659
+ begin
660
+ require 'tzinfo'
661
+ rescue LoadError
662
+ raise ArgumentError,
663
+ "format_date: IANA timeZone #{tz.inspect} requires the tzinfo gem (~> 2.0)"
664
+ end
665
+ begin
666
+ zone = TZInfo::Timezone.get(tz)
667
+ rescue TZInfo::InvalidTimezoneIdentifier
668
+ raise ArgumentError, "format_date: unresolvable timeZone #{tz.inspect}"
669
+ end
670
+ zone.period_for_utc(t.utc).observed_utc_offset
671
+ end
672
+
631
673
  # -----------------------------------------------------------------
632
674
  # Array / String method helpers
633
675
  # -----------------------------------------------------------------
@@ -730,6 +772,57 @@ module BarefootJS
730
772
  string(recv).each_char.sum { |c| c.ord > 0xFFFF ? 2 : 1 }
731
773
  end
732
774
 
775
+ # Runtime-polymorphic element/key access for `arr[index]` /
776
+ # `hash[key]` (`emitIndexAccessRuby`, expr/operand.ts). Row hashes
777
+ # deserialize with `symbolize_names: true`, so a dynamic key whose
778
+ # runtime value is a String (e.g. a destructured `.map()` param used
779
+ # as a key, `tone[k]`) misses a Symbol-keyed Hash outright -- and the
780
+ # shared analyzer can't tell at compile time whether an index will
781
+ # turn out to be a string key or a numeric index (it types a
782
+ # destructured param `{kind:'unknown'}`), so no compile-time branch
783
+ # can pick the right access form (#2491). Mirrors `getFieldValue`'s
784
+ # (Go adapter, bf.go) case-tolerant lookup and Twig's `attribute()`:
785
+ # for a Hash, try the key as-is, then as a Symbol, then as a String;
786
+ # for an Array, index numerically; anything else has no lookup to
787
+ # perform.
788
+ def get(collection, key)
789
+ return nil if key.nil?
790
+
791
+ case collection
792
+ when Hash
793
+ return collection[key] if collection.key?(key)
794
+
795
+ sym = key.respond_to?(:to_sym) ? key.to_sym : nil
796
+ return collection[sym] if sym && collection.key?(sym)
797
+
798
+ str = key.to_s
799
+ return collection[str] if collection.key?(str)
800
+
801
+ nil
802
+ when Array
803
+ # Only an INTEGRAL index reads an element. `key.to_i` would be
804
+ # wrong on both ends: it coerces a non-numeric String to 0
805
+ # (`arr["nope"]` must be nil, not the first element) and it
806
+ # truncates a fractional number (JS `arr[1.2]` is a property
807
+ # lookup, i.e. undefined -- not index 1).
808
+ idx =
809
+ case key
810
+ when Integer then key
811
+ when Numeric then (key % 1).zero? ? key.to_i : nil
812
+ when String then (key =~ /\A-?\d+\z/ ? key.to_i : nil)
813
+ end
814
+ return nil if idx.nil?
815
+
816
+ # JS-semantics negative index is "not found" (`arr[-1] ===
817
+ # undefined`), NOT Ruby's native from-the-end wraparound -- guard
818
+ # it explicitly so this stays a superset of bracket access rather
819
+ # than a divergent one.
820
+ return nil if idx.negative?
821
+
822
+ collection[idx]
823
+ end
824
+ end
825
+
733
826
  # Mirrors Hono's own CSS-injection guard (`hono/jsx/utils.ts`'s
734
827
  # `hasUnsafeStyleValue` -- the ORACLE a dynamic `style={{...}}` value
735
828
  # must match, #2261): a hand-rolled structural scan for characters that
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barefoot_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.0
4
+ version: 0.30.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - kobaken
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-20 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2026-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tzinfo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
13
41
  description: Engine-agnostic BarefootJS server runtime targeting ERB, ported from
14
42
  packages/adapter-perl/lib/BarefootJS.pm.
15
43
  email: