barefoot_js 0.18.4 → 0.18.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75f8d84f1a06dd1e2dcd614cb73a94506f02a93cd0e36b2ec8f79c982f3886d9
4
- data.tar.gz: c58250e3c14adb29e69fb0821ffbee94c02c1d24b72639ad9ec732d5984dd9c9
3
+ metadata.gz: 25b9687ad06be1cbb4af5cccab3d8caa83e038ed2b030ecb83dd4a7430f75175
4
+ data.tar.gz: cedfce0556b406f8b7c32d3cf936adcc50680006c123244315bb90fc1b1e8f05
5
5
  SHA512:
6
- metadata.gz: 9d920d1a38684ec644876e05fec43b1624bdb0c000cdd6f1ca6c14f6f89323877422ad7c4dd0b23a7d08f17771def17c02090ac5c424128f951636be7c8629a5
7
- data.tar.gz: 4aece46d06c426ef3f42eeabf79a559e623e815ea87b4d59880707845ecc21f380669e97c3657831a3d28960d6e3b8b0cba81f799c1cada4d6a2fe4071b04ba5
6
+ metadata.gz: 8048f1a7bafccb96cde14303b903d10f24e857999208bad02c1d429af4135921eebdeee6440606da524569727258096bce6d2c253b1b6ca0e1e4cd14d650b0d1
7
+ data.tar.gz: 7044ba378260461827af82e1632ab5ffc017800d4791d2e8765c16e5adbb7528565a66b3470ebfeb429ec2b8659b5706da3ac3f2031cb23e1e5c9e3a68fca4ef
@@ -13,15 +13,25 @@ module BarefootJS
13
13
  # operations the runtime delegates to, targeting Ruby stdlib ERB:
14
14
  #
15
15
  # encode_json(data) -> JSON string (injectable encoder)
16
- # mark_raw(str) -> identity (ERB has no "safe string"
17
- # wrapper type -- ERB's own `<%=` is
18
- # NOT auto-escaping, so the compiled
19
- # templates that need escaping call
20
- # `bf.h(...)` explicitly; `mark_raw`
21
- # only exists so runtime helpers that
22
- # already produce finished HTML --
23
- # e.g. spread_attrs -- share one
24
- # interface with the Kolon/EP ports)
16
+ # mark_raw(str) -> wraps in BarefootJS::SafeString --
17
+ # ERB's own `<%=` is NOT auto-escaping,
18
+ # so most compiled templates call
19
+ # `bf.h(...)` explicitly instead of
20
+ # relying on a safe-string bypass; the
21
+ # wrapper exists for the one path that
22
+ # DOES need one -- a named-slot /
23
+ # children value captured in a parent
24
+ # template and forwarded into a
25
+ # child's vars Hash, where the child
26
+ # reads it back through the generic
27
+ # `bf.h(...)` text-expression path
28
+ # (`Context#h` unwraps SafeString to
29
+ # skip re-escaping) -- and so that
30
+ # runtime helpers which already
31
+ # produce finished HTML (e.g.
32
+ # spread_attrs) share one
33
+ # `backend.mark_raw(...)` interface
34
+ # with the Kolon/EP ports
25
35
  # materialize(value) -> resolve a captured-children value
26
36
  # to a string
27
37
  # render_named(name, bf, vars) -> render `<name>.erb` with `bf` and
@@ -58,13 +68,12 @@ module BarefootJS
58
68
  @json_encoder.call(data)
59
69
  end
60
70
 
61
- # ERB has no "already-safe" string wrapper the way Kolon's `mark_raw`
62
- # or Mojo::ByteStream do -- stdlib ERB's `<%=` never auto-escapes, so
63
- # there is nothing to opt out of. Identity, kept only so runtime
64
- # helpers (`spread_attrs`) share one `backend.mark_raw(...)` call
65
- # shape across every BarefootJS backend port.
71
+ # See the class docstring's `mark_raw` entry: wraps in
72
+ # `BarefootJS::SafeString` so `Context#h` recognises and skips
73
+ # re-escaping already-finished HTML forwarded across a
74
+ # parent/child template boundary.
66
75
  def mark_raw(str)
67
- str
76
+ BarefootJS::SafeString.new(str.to_s)
68
77
  end
69
78
 
70
79
  # JSX children captured by the adapter's buffer-slice capture
@@ -188,7 +188,20 @@ module BarefootJS
188
188
  return Float::INFINITY if t == 'Infinity' || t == '+Infinity'
189
189
  return -Float::INFINITY if t == '-Infinity'
190
190
  return Integer(t, 16) if t =~ HEX_STRING_RE
191
- return Float(t) if t =~ NUMERIC_STRING_RE
191
+
192
+ if t =~ NUMERIC_STRING_RE
193
+ # Ruby's Float() rejects a trailing decimal point ("5.", "5.e3"),
194
+ # while JS's Number() accepts it (treating the fractional part as
195
+ # empty). Strip a "." that isn't followed by a digit before
196
+ # converting, so the accepted grammar stays identical to JS but the
197
+ # conversion itself never raises.
198
+ normalized = t.sub(/\.(?=\z|[eE])/, '')
199
+ begin
200
+ return Float(normalized)
201
+ rescue ArgumentError, TypeError
202
+ return Float::NAN
203
+ end
204
+ end
192
205
 
193
206
  Float::NAN
194
207
  end
data/lib/barefoot_js.rb CHANGED
@@ -25,6 +25,18 @@ require 'barefoot_js/search_params'
25
25
  # runtime carries -- a Ruby `true`/`false` IS a boolean, distinguishable
26
26
  # from `0`/`1` for free.
27
27
  module BarefootJS
28
+ # Marker wrapper for a string that is ALREADY finished HTML and must not
29
+ # be re-escaped by `Context#h` -- e.g. a named-slot / children capture
30
+ # (`renderComponent`'s output-buffer slice) forwarded from a parent
31
+ # template into a child's vars Hash. Stdlib ERB's `<%=` has no built-in
32
+ # "safe string" concept the way Twig's `Markup` or Kolon's `mark_raw`
33
+ # do, so the escape decision that elsewhere falls out of the template
34
+ # engine has to be carried on the VALUE itself here; see
35
+ # `Backend::Erb#mark_raw`, which is what actually wraps a string in this
36
+ # class.
37
+ class SafeString < String
38
+ end
39
+
28
40
  # Context is the `bf` object every compiled `.erb` template receives as a
29
41
  # local. One instance per render (root or child); `render_child` /
30
42
  # `register_components_from_manifest` construct a fresh child instance
@@ -391,8 +403,13 @@ module BarefootJS
391
403
  # HTML-escaping helper for text interpolation (`<%= bf.h(expr) %>` --
392
404
  # stdlib ERB does not auto-escape). JS-style stringification via
393
405
  # `string` (numbers per JS Number#toString, nil -> "", booleans ->
394
- # "true"/"false"), then HTML-escaped.
406
+ # "true"/"false"), then HTML-escaped. A `SafeString` (already-finished
407
+ # HTML forwarded from a parent's capture -- see that class's docstring)
408
+ # passes through unescaped, matching Twig/Blade/Kolon's safe-string
409
+ # bypass on their own auto-escaping `{{ }}`/`<: :>` output tags.
395
410
  def h(value)
411
+ return value if value.is_a?(SafeString)
412
+
396
413
  html_escape(string(value))
397
414
  end
398
415
 
@@ -430,6 +447,34 @@ module BarefootJS
430
447
  finite_number?(n) ? (n + 0.5).floor : n
431
448
  end
432
449
 
450
+ # `Math.min(a, b)` / `Math.max(a, b)` -- two-arg forms only (#2168
451
+ # math-methods). JS returns NaN if either operand is NaN. `number()`
452
+ # may return a plain Integer (no `#nan?`), so guard like
453
+ # `finite_number?` above rather than calling `#nan?` unconditionally.
454
+ def min(a, b)
455
+ x = number(a)
456
+ y = number(b)
457
+ return x if nan_number?(x)
458
+ return y if nan_number?(y)
459
+
460
+ x < y ? x : y
461
+ end
462
+
463
+ def max(a, b)
464
+ x = number(a)
465
+ y = number(b)
466
+ return x if nan_number?(x)
467
+ return y if nan_number?(y)
468
+
469
+ x > y ? x : y
470
+ end
471
+
472
+ # `Math.abs()` (#2168 math-methods).
473
+ def abs(value)
474
+ n = number(value)
475
+ nan_number?(n) ? n : n.abs
476
+ end
477
+
433
478
  # -----------------------------------------------------------------
434
479
  # Array / String method helpers
435
480
  # -----------------------------------------------------------------
@@ -563,13 +608,22 @@ module BarefootJS
563
608
  out
564
609
  end
565
610
 
566
- # `Array.prototype.slice(start, end?)`. Mirrors the Go/Perl `bf_slice` /
567
- # `slice` arithmetic so adapter output stays symmetric.
611
+ # `Array.prototype.slice(start, end?)` AND `String.prototype.slice`
612
+ # (the `string-slice` divergence) -- the adapter emits the same
613
+ # `bf_slice` call for both receiver shapes (it can't disambiguate
614
+ # string vs. array at compile time), so this dispatches on Ruby
615
+ # class, mirroring `includes` above. Mirrors the Go/Perl `bf_slice`
616
+ # / `slice` arithmetic so adapter output stays symmetric.
617
+ # `String#length` / `#[]` already index by character (not byte) for
618
+ # a UTF-8-encoded string, matching JS except for astral-plane input
619
+ # (the same divergence boundary every other adapter's pad/trim
620
+ # helpers already accept).
568
621
  def slice(recv, start, end_ = nil)
569
- return [] unless recv.is_a?(Array)
622
+ return [] unless recv.is_a?(Array) || recv.is_a?(String)
570
623
 
624
+ empty = recv.is_a?(String) ? '' : []
571
625
  len = recv.length
572
- return [] if len.zero?
626
+ return empty if len.zero?
573
627
 
574
628
  s = start.nil? ? 0 : start.to_i
575
629
  s = len + s if s.negative?
@@ -581,7 +635,7 @@ module BarefootJS
581
635
  e = 0 if e.negative?
582
636
  e = len if e > len
583
637
 
584
- return [] if s >= e
638
+ return empty if s >= e
585
639
 
586
640
  recv[s...e]
587
641
  end
@@ -663,6 +717,21 @@ module BarefootJS
663
717
  string(recv).gsub(/\A\p{Space}+|\p{Space}+\z/, '')
664
718
  end
665
719
 
720
+ # `String.prototype.trimStart()` / `.trimEnd()` -- the one-sided
721
+ # siblings of `trim` above (#2183 follow-up), same `\p{Space}` regex
722
+ # restricted to one side.
723
+ def trim_start(recv)
724
+ return '' if recv.nil? || recv.is_a?(Array) || recv.is_a?(Hash)
725
+
726
+ string(recv).sub(/\A\p{Space}+/, '')
727
+ end
728
+
729
+ def trim_end(recv)
730
+ return '' if recv.nil? || recv.is_a?(Array) || recv.is_a?(Hash)
731
+
732
+ string(recv).sub(/\p{Space}+\z/, '')
733
+ end
734
+
666
735
  # `Number.prototype.toFixed(digits)` -- fixed-decimal string with
667
736
  # zero-padding, rounding half toward +Infinity (matching `round`).
668
737
  def to_fixed(value, digits = 0)
@@ -741,6 +810,38 @@ module BarefootJS
741
810
  s[0...idx] + n + s[(idx + o.length)..]
742
811
  end
743
812
 
813
+ # `String.prototype.replaceAll(pattern, replacement)` -- string-pattern
814
+ # form only (#2182), replacing EVERY occurrence (the all-occurrences
815
+ # sibling of `replace` above). Deliberately NOT `String#gsub`: Ruby's
816
+ # `gsub` interprets `\1` / `\&` backreference syntax in the replacement
817
+ # even for a literal string pattern (`"abc".gsub("b", "\\1")` -> "ac",
818
+ # not the literal "\1"), which would diverge from `.replace`'s literal
819
+ # splice above and from the other backends' literal treatment. The
820
+ # index/splice loop keeps the replacement literal, matching `replace`.
821
+ # An empty pattern inserts at every boundary, including before the
822
+ # first and after the last character (`"abc".replaceAll("", "X")` ->
823
+ # "XaXbXcX"), matching JS.
824
+ def replace_all(recv, pattern, replacement)
825
+ s = recv.nil? ? '' : string(recv)
826
+ o = pattern.nil? ? '' : string(pattern)
827
+ n = replacement.nil? ? '' : string(replacement)
828
+ return ([''] + s.chars + ['']).join(n) if o.empty?
829
+
830
+ # `+''` (not the frozen `''` literal under frozen_string_literal)
831
+ # so `<<` can append in place instead of `+=` reallocating a new
832
+ # string each iteration (quadratic for long inputs / many matches).
833
+ out = +''
834
+ pos = 0
835
+ loop do
836
+ idx = s.index(o, pos)
837
+ break if idx.nil?
838
+
839
+ out << s[pos...idx] << n
840
+ pos = idx + o.length
841
+ end
842
+ out << s[pos..]
843
+ end
844
+
744
845
  # `queryHref(base, { ... })` (#2042) -- build "base?k=v&..." from a flat
745
846
  # list of (guard, key, value) triples. A pair is included iff its guard
746
847
  # is truthy AND its value is a non-empty string. A value may instead be
@@ -978,6 +1079,10 @@ module BarefootJS
978
1079
  !(n.respond_to?(:nan?) && n.nan?) && !(n.respond_to?(:infinite?) && n.infinite?)
979
1080
  end
980
1081
 
1082
+ def nan_number?(n)
1083
+ n.respond_to?(:nan?) && n.nan?
1084
+ end
1085
+
981
1086
  def html_escape(s)
982
1087
  s.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;').gsub('"', '&#34;').gsub("'", '&#39;')
983
1088
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barefoot_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.4
4
+ version: 0.18.7
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-08 00:00:00.000000000 Z
11
+ date: 2026-07-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Engine-agnostic BarefootJS server runtime targeting ERB, ported from
14
14
  packages/adapter-perl/lib/BarefootJS.pm.