@barefootjs/jinja 0.23.0 → 0.24.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/jinja",
3
- "version": "0.23.0",
3
+ "version": "0.24.1",
4
4
  "description": "Jinja2 adapter for BarefootJS — compiles IR to .jinja templates and ships the Python BarefootJS rendering runtime; runs under any Python web framework (Flask, etc.)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,14 +53,14 @@
53
53
  "directory": "packages/adapter-jinja"
54
54
  },
55
55
  "dependencies": {
56
- "@barefootjs/shared": "0.23.0"
56
+ "@barefootjs/shared": "0.24.1"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@barefootjs/jsx": ">=0.2.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@barefootjs/adapter-tests": "0.1.0",
63
- "@barefootjs/jsx": "0.23.0",
63
+ "@barefootjs/jsx": "0.24.1",
64
64
  "typescript": "^5.0.0"
65
65
  }
66
66
  }
@@ -959,15 +959,28 @@ class BarefootJS:
959
959
  return 0
960
960
 
961
961
  _FORMAT_DATE_TZ_RE = re.compile(r"^([+-])(\d{2}):(\d{2})$")
962
- _FORMAT_DATE_TOKEN_RE = re.compile(r"YYYY|MM|DD|M|D")
963
-
964
- def format_date(self, recv: Any, pattern: str, tz: str) -> str:
965
- """`format_date(recv, pattern, tz)` -- the lowering target for a
966
- `formatDate(date, pattern, timeZone)` call (#2324, spec entry
967
- "format_date"). `recv` follows the same receiver contract as `date`
968
- above -- this runtime's own `datetime` or an ISO-8601 string; a nil
969
- or unparseable receiver renders `''` (never a crash, never "now").
970
- Mirrors packages/client/src/format-date.ts byte-for-byte.
962
+ _FORMAT_DATE_TOKEN_RE = re.compile(r"YYYY|MMMM|MMM|MM|DD|dddd|ddd|M|D")
963
+
964
+ # `names`-table section offsets (spec/template-helpers.md "format_date",
965
+ # #2334) -- mirrors packages/client/src/format-date.ts's
966
+ # MONTHS_WIDE/MONTHS_ABBR/WEEKDAYS_WIDE/WEEKDAYS_ABBR constants.
967
+ _FORMAT_DATE_MONTHS_WIDE = 0
968
+ _FORMAT_DATE_MONTHS_ABBR = 12
969
+ _FORMAT_DATE_WEEKDAYS_WIDE = 24
970
+ _FORMAT_DATE_WEEKDAYS_ABBR = 31
971
+
972
+ def format_date(
973
+ self, recv: Any, pattern: str, tz: str, names: Optional[list] = None
974
+ ) -> str:
975
+ """`format_date(recv, pattern, tz, names)` -- the lowering target for
976
+ a `formatDate(date, pattern, timeZone, names)` call (#2324 numeric
977
+ tokens, #2334 name tokens; spec entry "format_date"). `recv` follows
978
+ the same receiver contract as `date` above -- this runtime's own
979
+ `datetime` or an ISO-8601 string; a nil or unparseable receiver
980
+ renders `''` (never a crash, never "now"). Mirrors
981
+ packages/client/src/format-date.ts byte-for-byte. Canonical arity is
982
+ 4 -- the lowering always supplies `tz` and `names` (defaulting
983
+ `'UTC'` and `[]`).
971
984
 
972
985
  `tz` is `'UTC'` or a fixed offset matching `±HH:MM`. The helper is
973
986
  total: any other value -- an IANA zone name, a malformed offset --
@@ -981,15 +994,34 @@ class BarefootJS:
981
994
  a positive offset on 9999-12-31 lands in year 10000, past
982
995
  `datetime.max`, and must render `10000-…` like the JS reference
983
996
  instead of overflowing (golden vector "positive offset pushes the
984
- far-future instant past year 9999").
985
-
986
- `pattern` is scanned longest-match over `YYYY|MM|DD|M|D`
987
- (`_FORMAT_DATE_TOKEN_RE`, alternation ordered so the 2/4-char
988
- tokens win before their single-char prefixes); every other
989
- character -- including multi-byte ones like 年/月/日 -- passes
990
- through literally. `YYYY` is `abs(year)` zero-padded to 4 digits,
991
- `-`-prefixed for a negative year; `MM`/`DD` zero-pad to 2; `M`/`D`
992
- are bare."""
997
+ far-future instant past year 9999"). The weekday used by `dddd`/
998
+ `ddd` comes from the SAME integer path -- `(shifted_ms // 86_400_000
999
+ + 4) % 7` (Python floor division; `+4` because epoch day 0,
1000
+ 1970-01-01, is a Thursday, and the table is Sunday-first so
1001
+ `weekday == 0` must mean Sunday) -- rather than re-deriving it from
1002
+ `yoe`/`doy`, so it stays correct across the same year-10000
1003
+ overflow boundary the civil-from-days math above already handles.
1004
+
1005
+ `pattern` is scanned longest-match over
1006
+ `YYYY|MMMM|MMM|MM|DD|dddd|ddd|M|D` (`_FORMAT_DATE_TOKEN_RE`,
1007
+ alternation ordered so longer tokens win before their shorter
1008
+ prefixes); every other character -- including multi-byte ones like
1009
+ 年/月/日 -- passes through literally. `YYYY` is `abs(year)`
1010
+ zero-padded to 4 digits, `-`-prefixed for a negative year; `MM`/`DD`
1011
+ zero-pad to 2; `M`/`D` are bare. `MMMM`/`MMM` read `names[month-1]`
1012
+ / `names[12+month-1]` (wide/abbreviated month name); `dddd`/`ddd`
1013
+ read `names[24+weekday]` / `names[31+weekday]` (wide/abbreviated
1014
+ weekday name, Sunday-first) -- `names` is the flat table documented
1015
+ on the module's `formatDate` JS sibling: `[0..11]` wide months,
1016
+ `[12..23]` abbreviated months, `[24..30]` wide weekdays, `[31..37]`
1017
+ abbreviated weekdays. An index past the end of (or an altogether
1018
+ missing) `names` table renders `''` for that token, never an
1019
+ `IndexError`."""
1020
+ names = names or []
1021
+
1022
+ def _name_at(index: int) -> str:
1023
+ return names[index] if 0 <= index < len(names) else ""
1024
+
993
1025
  if isinstance(recv, datetime.datetime):
994
1026
  dt = recv
995
1027
  else:
@@ -1020,11 +1052,23 @@ class BarefootJS:
1020
1052
  month = mp + 3 if mp < 10 else mp - 9
1021
1053
  year = yoe + era * 400 + (1 if month <= 2 else 0)
1022
1054
  yyyy = ("-" if year < 0 else "") + f"{abs(year):04d}"
1055
+ # Weekday from the SAME integer path as the civil-from-days fields
1056
+ # above (NOT re-derived from yoe/doy) -- 0=Sunday, matching the
1057
+ # table's Sunday-first layout. `(shifted_ms // 86_400_000)` is the
1058
+ # signed epoch-day count (Python floor division, exact for negative
1059
+ # epochs); `+4` anchors it since epoch day 0 (1970-01-01) is a
1060
+ # Thursday.
1061
+ days = shifted_ms // 86_400_000
1062
+ weekday = (days + 4) % 7
1023
1063
 
1024
1064
  def _sub(match: "re.Match[str]") -> str:
1025
1065
  token = match.group(0)
1026
1066
  if token == "YYYY":
1027
1067
  return yyyy
1068
+ if token == "MMMM":
1069
+ return _name_at(self._FORMAT_DATE_MONTHS_WIDE + month - 1)
1070
+ if token == "MMM":
1071
+ return _name_at(self._FORMAT_DATE_MONTHS_ABBR + month - 1)
1028
1072
  if token == "MM":
1029
1073
  return f"{month:02d}"
1030
1074
  if token == "M":
@@ -1033,6 +1077,10 @@ class BarefootJS:
1033
1077
  return f"{day:02d}"
1034
1078
  if token == "D":
1035
1079
  return str(day)
1080
+ if token == "dddd":
1081
+ return _name_at(self._FORMAT_DATE_WEEKDAYS_WIDE + weekday)
1082
+ if token == "ddd":
1083
+ return _name_at(self._FORMAT_DATE_WEEKDAYS_ABBR + weekday)
1036
1084
  return token
1037
1085
 
1038
1086
  return self._FORMAT_DATE_TOKEN_RE.sub(_sub, pattern)
@@ -139,7 +139,7 @@ BINDINGS = {
139
139
  "abs": bf.abs,
140
140
  "to_fixed": lambda *a: bf.to_fixed(*a),
141
141
  "date": lambda recv, op: bf.date(recv, op),
142
- "format_date": lambda recv, pattern, tz: bf.format_date(recv, pattern, tz),
142
+ "format_date": lambda recv, pattern, tz, names=None: bf.format_date(recv, pattern, tz, names),
143
143
  "lower": bf.lc,
144
144
  "upper": bf.uc,
145
145
  "trim": bf.trim,