barefoot_js 0.18.3 → 0.18.5
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 +4 -4
- data/lib/barefoot_js/backend/erb.rb +24 -15
- data/lib/barefoot_js/evaluator.rb +14 -1
- data/lib/barefoot_js.rb +111 -6
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 047612ec9d85f8816540238656d6d4e2b76de5bd6286675ef46d5a2f2bebc11f
|
|
4
|
+
data.tar.gz: 64b58c9b1d20a09c8a4ba7b9389dd9eef8785a7970ab9d19cc8fb266237c3d0a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98e063e76ba043324c611d7c6dd4c2c20e42ec5de2c34dbbbe875fbb27a30783a2b6d55a916016b9159bfb8033c7d50d25707df5c754172e4eb1f54e8f2233e0
|
|
7
|
+
data.tar.gz: b06714c0af748ebbd1222116598ba0a7ed1ca024088e78edea1e6e91faa64a6903f3d1324e8752b5c7f963b11ea5b162e21072696435d5fdc87b7fbb567e88dc
|
|
@@ -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) ->
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
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
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
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
|
-
|
|
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?)
|
|
567
|
-
# `slice`
|
|
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
|
|
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
|
|
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('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"').gsub("'", ''')
|
|
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
|
+
version: 0.18.5
|
|
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-
|
|
11
|
+
date: 2026-07-11 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.
|