@barefootjs/erb 0.21.3 → 0.23.0

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.
package/dist/index.js CHANGED
@@ -189261,15 +189261,15 @@ var erbAdapter = new ErbAdapter;
189261
189261
  // src/conformance-pins.ts
189262
189262
  var conformancePins = {
189263
189263
  "static-array-from-props": [
189264
- { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2087" }
189264
+ { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2321" }
189265
189265
  ],
189266
189266
  "static-array-from-props-with-component": [
189267
- { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2087" }
189267
+ { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2321" }
189268
189268
  ],
189269
189269
  "filter-nested-find-predicate": [
189270
- { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
189270
+ { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2320" }
189271
189271
  ],
189272
- "dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2215" }],
189272
+ "dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2319" }],
189273
189273
  "date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2274" }]
189274
189274
  };
189275
189275
  // src/render-divergences.ts
@@ -529,6 +529,80 @@ module BarefootJS
529
529
  end
530
530
  end
531
531
 
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/
536
+
537
+ # Longest-match pattern-token alternation (mirrors TOKEN_RE in
538
+ # packages/client/src/format-date.ts). Order matters: MM before M and DD
539
+ # before D so the 2-char token wins at a position where either could
540
+ # match -- Ruby's Onigmo engine, like JS's regex engine, resolves
541
+ # alternation leftmost-first (not POSIX leftmost-longest), so listing the
542
+ # longer alternative first is what makes "MM" consume both characters
543
+ # instead of two "M" matches.
544
+ FORMAT_DATE_TOKEN_RE = /YYYY|MM|DD|M|D/
545
+
546
+ # `format_date(recv, pattern, tz)` (#2324, spec entry "format_date" in
547
+ # spec/template-helpers.md) -- the lowering target for
548
+ # `formatDate(date, pattern, timeZone)` (packages/client/src/format-date.ts,
549
+ # the JS-normative reference this must match byte-for-byte). Total and
550
+ # deterministic: no locale, no host timezone, no `Time.now`.
551
+ #
552
+ # recv: the same receiver contract as `date` above -- a native `Time` or
553
+ # an ISO-8601 string, normalized identically. A nil / unparseable
554
+ # receiver renders '' (never raises mid-render).
555
+ #
556
+ # tz: a fixed UTC offset `±HH:MM` shifts the instant by
557
+ # sign*(HH*60+MM) minutes; ANY other value -- 'UTC', an IANA zone name
558
+ # ('Asia/Tokyo'), or a malformed offset ('+9:00') -- normalizes to a
559
+ # zero-minute shift (UTC), so every backend degrades identically instead
560
+ # of dragging in host tzdata. The shifted instant's UTC calendar fields
561
+ # (not the original instant's) are what pattern tokens read -- the
562
+ # shifted UTC clock face IS the local clock face at that offset. `Time`
563
+ # arithmetic here is exact (Ruby represents the instant as a Rational,
564
+ # not a floor-divided epoch-millis integer), so there's no pre-1970
565
+ # negative-epoch floor-division trap to dodge the way a naive
566
+ # epoch-millis-div-86400000 implementation would hit.
567
+ #
568
+ # pattern: longest-match token substitution (`YYYY|MM|DD|M|D`); every
569
+ # other character -- including multi-byte ones like 年/月/日 -- passes
570
+ # through literally. `YYYY` is `abs(year)` zero-padded to 4 digits,
571
+ # `-`-prefixed for a negative year; `MM`/`DD` zero-pad to 2; `M`/`D` are
572
+ # bare.
573
+ def format_date(recv, pattern, tz)
574
+ t =
575
+ if recv.is_a?(Time)
576
+ recv
577
+ else
578
+ begin
579
+ Time.iso8601(recv.to_s)
580
+ rescue ArgumentError
581
+ nil
582
+ end
583
+ end
584
+ return '' if t.nil?
585
+
586
+ m = FORMAT_DATE_OFFSET_RE.match(tz.to_s)
587
+ offset_minutes = m ? (m[1] == '-' ? -1 : 1) * ((m[2].to_i * 60) + m[3].to_i) : 0
588
+
589
+ shifted = (t.utc + (offset_minutes * 60)).utc
590
+ year = shifted.year
591
+ month = shifted.mon
592
+ day = shifted.mday
593
+ yyyy = (year.negative? ? '-' : '') + year.abs.to_s.rjust(4, '0')
594
+
595
+ pattern.gsub(FORMAT_DATE_TOKEN_RE) do |token|
596
+ case token
597
+ when 'YYYY' then yyyy
598
+ when 'MM' then format('%02d', month)
599
+ when 'M' then month.to_s
600
+ when 'DD' then format('%02d', day)
601
+ when 'D' then day.to_s
602
+ end
603
+ end
604
+ end
605
+
532
606
  # -----------------------------------------------------------------
533
607
  # Array / String method helpers
534
608
  # -----------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/erb",
3
- "version": "0.21.3",
3
+ "version": "0.23.0",
4
4
  "description": "ERB (Embedded Ruby) adapter for BarefootJS — compiles IR to .erb templates and ships the Ruby rendering backend; runs under any Rack app (Sinatra, Rails)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,14 +54,14 @@
54
54
  "directory": "packages/adapter-erb"
55
55
  },
56
56
  "dependencies": {
57
- "@barefootjs/shared": "0.21.3"
57
+ "@barefootjs/shared": "0.23.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@barefootjs/jsx": ">=0.2.0"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@barefootjs/adapter-tests": "0.1.0",
64
- "@barefootjs/jsx": "0.21.3",
64
+ "@barefootjs/jsx": "0.23.0",
65
65
  "typescript": "^5.0.0"
66
66
  }
67
67
  }
@@ -39,17 +39,17 @@ export const conformancePins: ConformancePins = {
39
39
  // destructure gate merely exposes — it reproduces identically with a
40
40
  // non-destructured param (verified) — not a destructure-lowering
41
41
  // limitation, so it is NOT part of #2087's scope. Tracked as its own
42
- // gap under https://github.com/piconic-ai/barefootjs/issues/2087;
42
+ // gap under https://github.com/piconic-ai/barefootjs/issues/2321;
43
43
  // pinned honestly as BF101 (the adapter's own check, see `renderLoop`'s
44
44
  // "Loop array is a bare identifier..." comment) rather than faked as
45
45
  // BF104 or silently producing broken Ruby.
46
46
  'static-array-from-props': [
47
- { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2087' },
47
+ { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2321' },
48
48
  ],
49
49
  // BF103 (imported child in the loop body) no longer fires now that the
50
50
  // conformance harness passes `siblingTemplatesRegistered: true` (#2205).
51
51
  'static-array-from-props-with-component': [
52
- { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2087' },
52
+ { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2321' },
53
53
  ],
54
54
  // #2087 Phase B: `isLowerableLoopDestructure` now admits every fixed-
55
55
  // binding shape (any field/index depth — `destructure-array-index-in-map`,
@@ -69,9 +69,9 @@ export const conformancePins: ConformancePins = {
69
69
  // (`filter-nested-callback-predicate`) is NOT pinned: like mojo, ERB
70
70
  // lowers it to a real inline Ruby block predicate and must render to
71
71
  // Hono parity instead.
72
- // https://github.com/piconic-ai/barefootjs/issues/2038
72
+ // Faithful lowering tracked: https://github.com/piconic-ai/barefootjs/issues/2320 (successor to #2038)
73
73
  'filter-nested-find-predicate': [
74
- { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2038' },
74
+ { code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2320' },
75
75
  ],
76
76
  // #1467 demo-corpus context providers (`radio-group`, `accordion`,
77
77
  // `dialog`, `popover`, `select`, `dropdown-menu`, `combobox`,
@@ -101,8 +101,8 @@ export const conformancePins: ConformancePins = {
101
101
  // `dangerouslySetInnerHTML={{ __html: '...' }}` is spliced directly into
102
102
  // the template as trusted raw text (`resolveDangerousInnerHtml`, #2207).
103
103
  // A dynamic/signal-derived value still refuses with BF101 — see the
104
- // `dangerous-inner-html-dynamic` fixture/pin below (tracked: #2215).
105
- 'dangerous-inner-html-dynamic': [{ code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2215' }],
104
+ // `dangerous-inner-html-dynamic` fixture/pin below (tracked: #2319, successor to #2215).
105
+ 'dangerous-inner-html-dynamic': [{ code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2319' }],
106
106
  // #2273: a method call on a prop typed as a built-in host rich type
107
107
  // (Date, Map, …) has no catalogued lowering in any adapter — this is a
108
108
  // compiler-level refusal (`checkRichTypeMethodCalls`, wired ahead of