Skip to content

Feature/localize#45

Merged
magmacomputing merged 9 commits into
mainfrom
feature/localize
Jun 16, 2026
Merged

Feature/localize#45
magmacomputing merged 9 commits into
mainfrom
feature/localize

Conversation

@magmacomputing

@magmacomputing magmacomputing commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Extended .format() to accept native Intl.DateTimeFormatOptions, including timeZone/calendar.
    • Added {nano} support with BigInt-preserving epoch nanoseconds.
    • Added multi-locale parsing via locale: string | string[].
  • Bug Fixes
    • Improved locale-aware token parsing/normalization and safer native formatting fallbacks.
  • Documentation
    • Refreshed Tempo branding and CDN/import examples; expanded locale and ambiguity-resolution guidance.
    • Updated licensing/registry callouts and migration/plugin examples to match current activation flow.
  • Chores
    • Version bumps: root 3.2.0, library 3.1.2, Tempo 4.0.0; updated browser import maps to Tempo v4.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces Tempo 4.0.0 with breaking registry consolidation and extensive multilingual/Intl formatting improvements; consolidates top-level config keys into unified registry namespace; extends Tempo.format() with Intl.DateTimeFormatOptions and '{nano}'bigint support; refactors parser to use locale-specific monthMap/weekdayMap for multi-locale parsing; removes built-in ticker module in favor of premium @magmacomputing/tempo-plugin-ticker; adds license registry callouts; refreshes branding to tempo-logo.svg; bumps tempo to 4.0.0, library to 3.1.2.

Changes

Configuration Registry Consolidation (Breaking Change for 4.0.0)

Layer / File(s) Summary
Type contracts: BaseOptions registry expansion and field removal
packages/tempo/src/tempo.type.ts
Internal.BaseOptions removes top-level localize, format, parse, snippet, layout, event, period, ignore fields; expands registry to include snippets, layouts, events, periods, ignores alongside existing formats and locales; Internal.Config and Internal.Discovery remove corresponding engine configuration fields.
Init state extension: plural-key mapping and registry parsing
packages/tempo/src/support/support.init.ts
extendState() refactored to map plural input keys (snippets, layouts, events, periods, ignores) to singular parse targets; removes top-level key handling; maintains existing snippet pattern safety checks within new plural-key framework.
Tests: registry-scoped configuration in all test suites
packages/tempo/test/core/*, packages/tempo/test/discrete/*, packages/tempo/test/engine/*, packages/tempo/test/issues/*, packages/tempo/test/instance/*
Core config, sandbox factory, global options, and static getter tests updated to use registry.snippets, registry.layouts, registry.periods, registry.events; all functional alias, relative date, and issue-fix tests use nested registry: { events/periods: ... } instead of top-level options.
Documentation: registry-scoped configuration examples
packages/tempo/doc/tempo.config.md, packages/tempo/doc/tempo.parse.md, packages/tempo/doc/tempo.layout.md, packages/tempo/doc/sandbox-factory.md
Examples updated to show registry.periods, registry.snippets, registry.ignores, registry.layouts, registry.events in Tempo.init() and instance configuration; custom-alias and period-configuration examples refactored to nested structure.
Changelog 4.0.0: breaking changes for registry consolidation
packages/tempo/CHANGELOG.md
New 4.0.0 release section documents removal of legacy root-level configuration access, removal of Tempo.formats in favor of Tempo.registry.formats, and top-level formats option removal; includes internal architecture, security/licensing, and documentation/ecosystem subsections.

Intl Formatting API Extension

Layer / File(s) Summary
Type contracts: BigIntPattern enum and FormatType conditional
packages/tempo/src/support/support.enum.ts, packages/tempo/src/support/support.index.ts
BigIntPattern ('{nano}') introduced alongside NumericPattern; FormatType<K> updated to map BigIntPattern keys to bigint and fallback union expanded to string | number | bigint; BigIntPattern added to module re-exports.
Format overload declarations: Tempo.format and standalone export
packages/tempo/src/tempo.class.ts, packages/tempo/src/module/module.format.ts
Internal.Fmt broadened to accept Intl.DateTimeFormatOptions & { timeZone?; calendar? }; Tempo.format and standalone format() receive typed overloads for Intl.DateTimeFormatOptions, '{nano}'bigint, and NumericPatternnumber; argument normalization enables object-as-options swapping.
Runtime format implementation: timeZone/calendar enforcement and Intl fallback
packages/tempo/src/module/module.format.ts
fmt === undefined branch applies withTimeZone/withCalendar to zdt when config differs; prefers getDTF(locale, options).format(zdt) when options present, with try/catch fallback stripping timeZone/calendar before toLocaleString(); numeric coercion expands to BigIntPattern-matched templates.
Format tests: {nano} bigint and Intl options coverage
packages/tempo/test/instance/instance.format.test.ts
Existing {mmm}/{www} assertions retained with comment cleanup; new tests verify t.format('{nano}') returns bigint > 0n; new test validates t.format(arabicConfig) returns a string with minimum length under strict Temporal bounds.
Cookbook docs: Complex Native Intl Formatting section
packages/tempo/doc/tempo.cookbook.md
New section demonstrates passing Intl.DateTimeFormatOptions to Tempo.format(), with Temporal-vs-Tempo comparison examples and Japanese Reiwa era example; includes embedded license-registry callout before ticker plugin section.
Changelog 3.2.0: Intl formatting features
packages/tempo/CHANGELOG.md
New 3.2.0 section documents added Intl.DateTimeFormatOptions passthrough, memoized getDTF delegation, and BigInt-preserving {nano} implementation; fixes section describes defensive toLocaleString() polyfill fallback and numeric coercion for {nano}.

Multilingual Parsing with Locale-Specific Maps

Layer / File(s) Summary
Type contracts: locale as array and separated locale maps
packages/tempo/src/tempo.type.ts
Internal.BaseOptions.locale broadened to string | string[]; Internal.Match gains optional locale?: string field; Internal.Parse replaces localeMap with monthMap and weekdayMap, each mapping to { value: number; locale: string } objects.
Init state extension: multi-locale canonicalization and map clearing
packages/tempo/src/support/support.init.ts
locale option handling changed to accept array via asArray, canonicalizes each entry, filters invalid results; clearLocalization() now deletes monthMap and weekdayMap instead of localeMap.
Snippet generation refactored to memoized multi-locale generator
packages/tempo/src/support/support.util.ts
Introduced memoized internal _generateLocalizedSnippets(localeKey) processing comma-separated keys; builds separate monthMap and weekdayMap per locale with normalized (lowercased/accent-stripped) keys and { value, locale } objects; exports generateLocalizedSnippets(locales: string | string[]).
Localized parsing initialization: token regex merge and map assignment
packages/tempo/src/support/support.init.ts
Localized resource generation operates on locale array; assigns returned monthMap and weekdayMap to state.parse; rebuilds Token.mm and Token.wkd regex overrides by merging default token placeholders with locale-specific snippet fragments; clears localization when all locales are English.
Parser engine: weekday/month normalization using split maps
packages/tempo/src/engine/engine.normalizer.ts
normalizeMatch now uses state.parse.weekdayMap and state.parse.monthMap instead of generic localeMap; treats map values as { value, locale } objects; records locale attribution in accumulateResult diagnostics.
Tempo._locale helper: accepts array and canonicalizes first entry
packages/tempo/src/tempo.class.ts
Tempo._locale updated to accept string | string[]; when given array, canonicalizes only the first element; fallback chain updated to include primaryLocale.
Parse module: guard bypass condition uses monthMap instead of localize flag
packages/tempo/src/module/module.parse.ts
_ParseEngine.conform strict global guard bypass condition updated from checking state.parse.localize to checking state.parse.monthMap non-empty.
Format module: remove auto-insert of locale modifier when localize flag was enabled
packages/tempo/test/discrete/format.test.ts
Prior behavior auto-inserting locale modifier when config.format.localize was enabled is removed; explicit :locale modifiers now required in format tokens; tests updated to show explicit :locale usage.
Docs: multi-locale parsing, ambiguity resolution, and locale-driven behavior
packages/tempo/doc/tempo.parse.md, packages/tempo/doc/tempo.locale.md, packages/tempo/doc/tempo.month-day.md
tempo.parse.md shows Tempo.init({ locale: ['fr-FR', 'es-ES'] }) array configuration with cross-locale collision warning; new comprehensive tempo.locale.md guide documents locale-driven ambiguity resolution, multi-lingual parsing via Intl, and locale-aware formatting; tempo.month-day.md expanded with US vs UK numeric-input examples and parse-planner override guidance.
Tests: multi-locale parsing with fallback to English
packages/tempo/test/discrete/parse.locale.test.ts
Prior test expecting English dates to fail under French localization changed to assert success; new tests verify parsing French+Spanish month names and fallback to English with multi-locale arrays.

Ticker Commercialization, License Registry & Branding

Layer / File(s) Summary
Remove built-in ticker module from documentation
packages/tempo/doc/tempo.modularity.md, packages/tempo/doc/tempo.term.md, packages/tempo/doc/tempo.shorthand.md, packages/tempo/doc/architecture.md
Deletes @magmacomputing/tempo/ticker from import examples and module list; removes "Terms in Tickers" subsection; drops ticker from Shorthand "Used in" list; updates Registration Gotcha and architecture examples to reference term and duration modules.
Premium plugin example with license requirement
packages/tempo/doc/tempo.plugin.md
Updates ticker example to use commercial @magmacomputing/tempo-plugin-ticker import with Tempo.init called with a required license parameter; adds embedded license-registry callout guiding users to obtain subscription/license key.
License registry HTML callouts across documentation
packages/tempo/doc/commercial.md, packages/tempo/doc/migration-guide.md, packages/tempo/doc/releases/v3.x.md, packages/tempo/doc/tempo.cookbook.md
Inserts styled HTML blocks with Tempo License Registry logo and link into commercial, migration, release, and cookbook pages; updates migration guide "Activate your License" step to specify obtaining free JWT license key.
Logo branding update to tempo-logo.svg
packages/tempo/.vitepress/config.ts, packages/tempo/index.md, packages/tempo/README.md
Replaces logo.svg with tempo-logo.svg in VitePress config (favicon + theme logo), hero image, and README header; adds "Zero-Bundle Localization" bullet to README "Why Tempo" section; adds sidebar navigation entry for new tempo.locale.md guide.
Version bumps and package updates: packages/tempo to 4.0.0, library to 3.1.2
packages/tempo/src/tempo.version.ts, packages/tempo/package.json, packages/library/package.json, package.json, packages/tempo/importmap.json, packages/tempo/public/bundle.index.html
Updates TEMPO_VERSION to 4.0.0; bumps packages/tempo to 4.0.0 with expanded keywords (formatting, i18n, localization, relative, extensible); bumps packages/library to 3.1.2; updates root package.json to 3.2.0; refines allowScripts versioning; updates import maps and CDN references from @3 to @4.
Documentation cleanup: math notation and ambiguity resolution guides
packages/tempo/doc/lazy-evaluation-pattern.md, packages/tempo/doc/releases/v2.x.md, packages/tempo/doc/tempo.benchmarks.md, packages/tempo/doc/tempo.planner.md, packages/tempo/doc/installation.md, packages/tempo/doc/releases/v4.x.md
Reformats LaTeX-style math notation to inline code throughout docs; adds "Lazy Creation" step to benchmark methodology; updates tempo.planner.md to emphasize deterministic control; refreshes installation guide with updated Temporal runtime guidance and CDN references; updates v4.x release notes with security/licensing and documentation subsections.
sequenceDiagram
  participant Caller
  participant format as format(fmt?, options?)
  participant normalize as normalize args
  participant getDTF as getDTF(locale, options)
  participant zdt as ZonedDateTime

  Caller->>format: format(options: Intl.DateTimeFormatOptions)
  format->>normalize: swap fmt↔options if fmt is object
  normalize-->>format: (fmt, options)
  format->>zdt: apply withTimeZone/withCalendar if config differs
  zdt-->>format: adjusted zdt
  format->>getDTF: create or retrieve DateTimeFormat
  getDTF-->>format: formatter instance
  format->>getDTF: .format(zdt)
  alt success
    getDTF-->>Caller: return formatted string
  else RangeError/TypeError
    format->>zdt: toLocaleString(locale, safeOptions without timeZone/calendar)
    zdt-->>Caller: return fallback string
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • magmacomputing/magma#44: Both PRs extend packages/tempo/src/module/module.format.ts and packages/tempo/src/tempo.class.ts to accept optional options parameter in Tempo.format() and format() for forwarding into Intl formatting logic.
  • magmacomputing/magma#43: Both PRs update Intl/DateTimeFormat integration in module.format.ts alongside localized snippet generation in support.util.ts for multi-locale parsing infrastructure.

🐇 Hop, hop—the logos change their face,
tempo-logo.svg takes its rightful place!
Config nests in registry now,
While parsing speaks a polyglot vow.
BigInt nanos sing with Intl's cheer,
And v4.0.0 is finally here! 🕒✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/localize

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tempo/src/module/module.format.ts`:
- Around line 91-96: The withTimeZone and withCalendar method calls on lines 92
and 95 can throw RangeError or TypeError when invalid identifiers are provided,
but these calls are outside the try/catch block that handles the Intl fallback
(lines 98-110). Wrap each call to zdt.withTimeZone(config.timeZone) and
zdt.withCalendar(config.calendar) in separate try/catch blocks to catch these
exceptions and allow the code to fall through to the existing fallback behavior
instead of crashing the formatter.
- Around line 37-39: The overload signature at line 37 declares that format()
returns bigint when called with '{nano}', but at runtime the '{nano}' template
is not registered in the FORMAT registry, so it's treated as a literal string
template. The token 'nano' is then resolved to a string value via toString() and
returned as a string at the end of the function, violating the type contract.
Change the return type of the first overload signature from bigint to string to
match the actual runtime behavior when '{nano}' is passed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e836c8fe-c944-48e3-8abd-a2d978be38d9

📥 Commits

Reviewing files that changed from the base of the PR and between a206b0f and e1518b5.

⛔ Files ignored due to path filters (2)
  • packages/tempo/img/tempo-logo.svg is excluded by !**/*.svg
  • packages/tempo/public/tempo-logo.svg is excluded by !**/*.svg
📒 Files selected for processing (19)
  • package.json
  • packages/library/package.json
  • packages/tempo/.vitepress/config.ts
  • packages/tempo/README.md
  • packages/tempo/doc/architecture.md
  • packages/tempo/doc/commercial.md
  • packages/tempo/doc/migration-guide.md
  • packages/tempo/doc/releases/v3.x.md
  • packages/tempo/doc/tempo.cookbook.md
  • packages/tempo/doc/tempo.modularity.md
  • packages/tempo/doc/tempo.plugin.md
  • packages/tempo/doc/tempo.shorthand.md
  • packages/tempo/doc/tempo.term.md
  • packages/tempo/index.md
  • packages/tempo/package.json
  • packages/tempo/src/module/module.format.ts
  • packages/tempo/src/support/support.enum.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.version.ts
💤 Files with no reviewable changes (1)
  • packages/tempo/doc/tempo.term.md

Comment thread packages/tempo/src/module/module.format.ts Outdated
Comment thread packages/tempo/src/module/module.format.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

3-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

version:sync now conflicts with split package versions (Tempo 3.2.0 vs root/library 3.1.2).

Line 3 sets the root to 3.1.2, but Line 21 still syncs both workspaces from npm_package_version. Running it will downgrade @magmacomputing/tempo and break the intended release contract (and downstream TEMPO_VERSION stamping).

Suggested fix
-    "version:sync": "node -e \"require('child_process').execSync('npm version ' + process.env.npm_package_version + ' -w `@magmacomputing/tempo` -w `@magmacomputing/library` --no-git-tag-version', {stdio:'inherit'})\"",
+    "version:sync:library": "npm version 3.1.2 -w `@magmacomputing/library` --no-git-tag-version",
+    "version:sync:tempo": "npm version 3.2.0 -w `@magmacomputing/tempo` --no-git-tag-version",
+    "version:sync": "npm run version:sync:library && npm run version:sync:tempo",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 3, The root package.json version on line 3 is set to
3.1.2, which conflicts with the `@magmacomputing/tempo` workspace that should be
at version 3.2.0. The version:sync mechanism uses npm_package_version from the
root, causing it to downgrade Tempo when synced. Update the version field on
line 3 from 3.1.2 to 3.2.0 to align with the intended Tempo release version and
prevent the downgrade conflict with the version:sync process.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tempo/src/support/support.init.ts`:
- Around line 234-239: The clearLocalization() function is only invoked when
resolvedLocales contains a single English locale, but when resolvedLocales is an
all-English array with multiple locales, the code at lines 368-369 skips
regeneration without clearing stale localization data. This leaves stale
monthMap and weekdayMap from previous non-English configurations. Modify the
logic to call clearLocalization() whenever all resolvedLocales are English
(check if resolvedLocales.every(locale => locale.split('-')[0] === 'en')), not
just when the length is 1. Apply this fix at both locations where English
locales are detected: within the conditional at line 238 for the single locale
case, and add the same clearLocalization() call when skipping regeneration for
all-English arrays at lines 368-369.

---

Outside diff comments:
In `@package.json`:
- Line 3: The root package.json version on line 3 is set to 3.1.2, which
conflicts with the `@magmacomputing/tempo` workspace that should be at version
3.2.0. The version:sync mechanism uses npm_package_version from the root,
causing it to downgrade Tempo when synced. Update the version field on line 3
from 3.1.2 to 3.2.0 to align with the intended Tempo release version and prevent
the downgrade conflict with the version:sync process.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f114c3d-9284-4b1a-bf4e-d6ae6f9da483

📥 Commits

Reviewing files that changed from the base of the PR and between 0501f00 and 2654a2e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • package.json
  • packages/tempo/CHANGELOG.md
  • packages/tempo/doc/tempo.parse.md
  • packages/tempo/package.json
  • packages/tempo/src/engine/engine.normalizer.ts
  • packages/tempo/src/support/support.init.ts
  • packages/tempo/src/support/support.util.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.type.ts
  • packages/tempo/src/tempo.version.ts
  • packages/tempo/test/discrete/parse.locale.test.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/tempo/package.json
  • packages/tempo/src/tempo.version.ts

Comment thread packages/tempo/src/support/support.init.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/tempo/doc/tempo.cookbook.md (1)

282-334: ⚠️ Potential issue | 🟡 Minor

Add test coverage for the exact outputs of Arabic and Japanese Intl formatting examples.

The .format() method overload does correctly accept Intl.DateTimeFormatOptions (confirmed in packages/tempo/src/module/module.format.ts line 16) and delegates to the native Intl.DateTimeFormat API. The implementation properly handles timezone and calendar constraints via the try-catch fallback pattern (lines 104–113).

However, the existing test for the Arabic example (instance.format.test.ts lines 48–68) only verifies that formatting doesn't crash and returns a non-empty string—it does not validate the exact output "الأربعاء، ٢٥ ديسمبر ٢٠٢٤" as claimed in the documentation. The Japanese Reiwa era example (lines 318–334) has no test coverage at all.

To match the documentation's claims, add assertions that verify the exact formatted outputs for both examples, ensuring that the numberingSystem: 'arab' and era: 'long' options produce the specific strings shown in the cookbook.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/doc/tempo.cookbook.md` around lines 282 - 334, The
documentation examples claim specific formatted outputs for Arabic numerals
(with numberingSystem: 'arab') and Japanese Reiwa era formatting (with era:
'long'), but the test coverage does not verify these exact strings. Update the
existing Arabic formatting test (which currently only checks for non-empty
output) to assert the exact expected output "الأربعاء، ٢٥ ديسمبر ٢٠٢٤", and add
a new test case for the Japanese Reiwa era example to verify it produces
"令和6年12月25日". Both tests should use the exact Intl.DateTimeFormatOptions objects
shown in the documentation (with locale, timeZone, calendar, era, and
numberingSystem as specified) to ensure the .format() method correctly handles
these complex internationalization scenarios.
packages/tempo/src/module/module.format.ts (1)

247-247: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Locale-array configs break term :locale resolution.

At Line 247, config?.locale?.split('-')[0] assumes locale is a string. packages/tempo/src/tempo.type.ts now allows locale: string | string[], so array inputs throw here and silently bypass term localization.

💡 Proposed fix
-								const lang = config?.locale?.split('-')[0] ?? 'en';
+								const localeInput = Array.isArray(config?.locale) ? config.locale[0] : config?.locale;
+								const lang = localeInput ? String(localeInput).split('-')[0] : 'en';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/src/module/module.format.ts` at line 247, The `lang`
assignment at line 247 assumes `config?.locale` is always a string, but the type
in tempo.type.ts now allows `locale: string | string[]`. When an array is
passed, the `.split('-')[0]` call fails because arrays do not have a split
method. Update the assignment to handle both string and array cases: if locale
is an array, extract the first element and then split it on the hyphen; if it is
a string, split it directly on the hyphen. This ensures the language code is
correctly extracted regardless of whether locale is a string or array input.
packages/tempo/doc/tempo.config.md (1)

171-175: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Options table is outdated and contradicts code examples in the same file.

Lines 171–175 list top-level event, period, snippet, and layout options, but the AI summary states this is "Tempo 4.0.0 with breaking registry consolidation," and the actual code examples in this document (lines 214–224, 258, 263) use registry.events, registry.periods, registry.layouts, registry.ignores. Additionally, the registry entry in the table describes only { formats?, locales? } but omits the nested keys (events, periods, snippets, layouts, ignores) shown in the type contract.

This table will mislead developers upgrading to v4.0.0 who expect top-level options to work.

🔧 Proposed fix for the options table

Update the table entries to reflect the current v4.0.0 registry structure and remove or deprecate the old top-level entries:

-| `event` | `Record<string, string \| Function>` | Built-in aliases | Custom date aliases merged into the event registry. |
-| `period` | `Record<string, string \| Function>` | Built-in aliases | Custom time aliases merged into the period registry. |
-| `snippet` | `Record<string, string \| RegExp>` | Built-in snippets | Custom snippet patterns used to compose parse layouts. |
-| `layout` | `Record<string, string \| RegExp>` | Built-in layouts | Custom parse layouts for date/time pattern matching. |
-| `registry` | `{ formats?, locales? }` | Built-in registries | Internal dictionary mappings (e.g., custom format tokens or localization dictionaries). |
+| `registry` | `{ events?, periods?, snippets?, layouts?, formats?, locales?, ignores? }` | Built-in registries | Custom data augmentation registries. `events` and `periods` for aliases, `snippets` and `layouts` for parse patterns, `formats` and `locales` for formatting/i18n, `ignores` for noise-word filtering. |

Alternatively, add a deprecation row before the table:

::: warning
**Breaking Change (v4.0.0)**: In Tempo v3.x, custom aliases and patterns were configured via top-level `event`, `period`, `snippet`, and `layout` options. These are now consolidated under the `registry` object. See [Section 5.1](`#custom-events-and-periods`) and [Section 5.3](`#noise-word-filtering`) for updated examples.
:::
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/doc/tempo.config.md` around lines 171 - 175, The options table
at lines 171–175 is outdated and contradicts the v4.0.0 code examples shown
later in the same document. Remove the separate `event`, `period`, `snippet`,
and `layout` rows from the table since these are now consolidated under the
`registry` object in v4.0.0. Update the `registry` row to document all nested
keys (`events`, `periods`, `snippets`, `layouts`, `ignores`) instead of only
listing `{ formats?, locales? }`. Additionally, add a deprecation warning
section before the table to clarify that top-level options from v3.x have been
consolidated under `registry` to help users upgrading to v4.0.0.
🧹 Nitpick comments (2)
packages/tempo/src/support/support.init.ts (1)

240-255: 💤 Low value

ReDoS mitigations are present but residual risk remains.

The static analysis flags new RegExp(pattern) at line 252 for potential ReDoS. The existing defenses (500-char length limit at line 244, backtrack pattern detection at line 248) provide reasonable protection. However, crafted patterns under 500 chars without detectable nested quantifiers could still cause slowdowns.

Since this processes user-provided registry.snippets configuration, the current mitigations strike a reasonable balance between usability and safety. Consider documenting that snippet patterns should be kept simple, or adding a timeout wrapper if snippets are ever sourced from untrusted input.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/src/support/support.init.ts` around lines 240 - 255, The
snippet pattern validation in the collect callback has ReDoS mitigations (length
limit and backtrack detection) but residual risk remains from crafted patterns
that evade these checks. Add documentation noting that snippet patterns should
be kept simple to mitigate ReDoS risk, and consider implementing a timeout
wrapper around the RegExp constructor call if snippets are ever sourced from
untrusted configuration inputs to provide defense-in-depth against potential
ReDoS attacks.

Source: Linters/SAST tools

packages/tempo/doc/tempo.cookbook.md (1)

230-244: ⚡ Quick win

Clarify when and where the FORMATS registry shortcut is resolved.

The "Tired of typing :locale?" tip (lines 230–244) shows a format string key 'ui-date' being passed directly to .format(). Confirm the documentation clearly explains:

  1. How Tempo resolves string keys to registered format templates (is it automatic, or does it require a specific initialization order?).
  2. Whether this lookup is case-sensitive and scoped globally or per instance.
  3. What error or behavior occurs if a key is not found in the registry.

The current text is clear but could benefit from a brief note on resolution scope/error handling to prevent user confusion.

Consider adding a single sentence such as: "Format keys are resolved case-sensitively from the global registry.formats, and throw an error if not found." This would make the feature more discoverable and less error-prone.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/doc/tempo.cookbook.md` around lines 230 - 244, The "Tired of
typing `:locale`?" tip section shows how to register and use format shortcuts
but lacks clarity on how Tempo resolves these string keys. Add a brief
explanatory sentence after the code example in the tip that clarifies: format
keys are resolved case-sensitively from the global registry.formats object, and
an error is thrown if the requested key is not found in the registry. This
additional detail will help users understand the lookup behavior and what to
expect if they encounter resolution failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tempo/CHANGELOG.md`:
- Around line 13-14: The CHANGELOG.md breaking change notes in lines 13-14 claim
that Tempo.formats and the top-level formats configuration key are completely
removed, but these members still exist as deprecated in the codebase
(Tempo.formats at packages/tempo/src/tempo.class.ts around line 965 and
formats/locales in the Discovery interface at packages/tempo/src/tempo.type.ts
around line 339). Update the CHANGELOG.md bullets to accurately reflect the
current state by changing "completely removed" and "entirely removed" language
to indicate these members are deprecated but still available, or alternatively
remove the deprecated members from the actual source code files if full removal
is the intended state. Ensure the breaking change documentation matches the
actual shipped API surface.

In `@packages/tempo/doc/installation.md`:
- Line 233: The JSDelivr CDN URL on line 233 points to `@4` but the accompanying
text incorrectly states "Locks to major version 3". Update the descriptive text
that follows the CDN URL from "Locks to major version 3" to "Locks to major
version 4" to correctly reflect the major version pinning in the URL reference.

In `@packages/tempo/test/discrete/parse.locale.test.ts`:
- Line 36: Remove the `localize: true` option from the Tempo constructor calls
at lines 15, 22, and 28 in the parse.locale.test.ts file. The `localize: true`
option is not defined in the BaseOptions interface and should not be used. Keep
the other options like `locale` and `anchor` that are properly supported. This
makes the test consistent with lines 36, 42, 46, and 51 which already follow the
correct pattern of using only the supported options.

---

Outside diff comments:
In `@packages/tempo/doc/tempo.config.md`:
- Around line 171-175: The options table at lines 171–175 is outdated and
contradicts the v4.0.0 code examples shown later in the same document. Remove
the separate `event`, `period`, `snippet`, and `layout` rows from the table
since these are now consolidated under the `registry` object in v4.0.0. Update
the `registry` row to document all nested keys (`events`, `periods`, `snippets`,
`layouts`, `ignores`) instead of only listing `{ formats?, locales? }`.
Additionally, add a deprecation warning section before the table to clarify that
top-level options from v3.x have been consolidated under `registry` to help
users upgrading to v4.0.0.

In `@packages/tempo/doc/tempo.cookbook.md`:
- Around line 282-334: The documentation examples claim specific formatted
outputs for Arabic numerals (with numberingSystem: 'arab') and Japanese Reiwa
era formatting (with era: 'long'), but the test coverage does not verify these
exact strings. Update the existing Arabic formatting test (which currently only
checks for non-empty output) to assert the exact expected output "الأربعاء، ٢٥
ديسمبر ٢٠٢٤", and add a new test case for the Japanese Reiwa era example to
verify it produces "令和6年12月25日". Both tests should use the exact
Intl.DateTimeFormatOptions objects shown in the documentation (with locale,
timeZone, calendar, era, and numberingSystem as specified) to ensure the
.format() method correctly handles these complex internationalization scenarios.

In `@packages/tempo/src/module/module.format.ts`:
- Line 247: The `lang` assignment at line 247 assumes `config?.locale` is always
a string, but the type in tempo.type.ts now allows `locale: string | string[]`.
When an array is passed, the `.split('-')[0]` call fails because arrays do not
have a split method. Update the assignment to handle both string and array
cases: if locale is an array, extract the first element and then split it on the
hyphen; if it is a string, split it directly on the hyphen. This ensures the
language code is correctly extracted regardless of whether locale is a string or
array input.

---

Nitpick comments:
In `@packages/tempo/doc/tempo.cookbook.md`:
- Around line 230-244: The "Tired of typing `:locale`?" tip section shows how to
register and use format shortcuts but lacks clarity on how Tempo resolves these
string keys. Add a brief explanatory sentence after the code example in the tip
that clarifies: format keys are resolved case-sensitively from the global
registry.formats object, and an error is thrown if the requested key is not
found in the registry. This additional detail will help users understand the
lookup behavior and what to expect if they encounter resolution failures.

In `@packages/tempo/src/support/support.init.ts`:
- Around line 240-255: The snippet pattern validation in the collect callback
has ReDoS mitigations (length limit and backtrack detection) but residual risk
remains from crafted patterns that evade these checks. Add documentation noting
that snippet patterns should be kept simple to mitigate ReDoS risk, and consider
implementing a timeout wrapper around the RegExp constructor call if snippets
are ever sourced from untrusted configuration inputs to provide defense-in-depth
against potential ReDoS attacks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 19bbf679-340f-49f1-b2c2-81ae61d9865b

📥 Commits

Reviewing files that changed from the base of the PR and between 52b0f8e and f9af652.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • packages/tempo/.vitepress/config.ts
  • packages/tempo/CHANGELOG.md
  • packages/tempo/README.md
  • packages/tempo/doc/architecture.md
  • packages/tempo/doc/installation.md
  • packages/tempo/doc/lazy-evaluation-pattern.md
  • packages/tempo/doc/releases/v2.x.md
  • packages/tempo/doc/releases/v4.x.md
  • packages/tempo/doc/sandbox-factory.md
  • packages/tempo/doc/tempo.benchmarks.md
  • packages/tempo/doc/tempo.config.md
  • packages/tempo/doc/tempo.cookbook.md
  • packages/tempo/doc/tempo.layout.md
  • packages/tempo/doc/tempo.locale.md
  • packages/tempo/doc/tempo.month-day.md
  • packages/tempo/doc/tempo.parse.md
  • packages/tempo/doc/tempo.planner.md
  • packages/tempo/importmap.json
  • packages/tempo/package.json
  • packages/tempo/public/bundle.index.html
  • packages/tempo/src/module/module.format.ts
  • packages/tempo/src/module/module.parse.ts
  • packages/tempo/src/support/support.init.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.type.ts
  • packages/tempo/src/tempo.version.ts
  • packages/tempo/test/core/config.test.ts
  • packages/tempo/test/core/global-options.test.ts
  • packages/tempo/test/core/sandbox-factory.test.ts
  • packages/tempo/test/core/static.getters.test.ts
  • packages/tempo/test/discrete/format.test.ts
  • packages/tempo/test/discrete/parse.locale.test.ts
  • packages/tempo/test/discrete/standalone_parse.test.ts
  • packages/tempo/test/engine/functional_alias_chaining.test.ts
  • packages/tempo/test/instance/relative_date.test.ts
  • packages/tempo/test/issues/infinite-loop.test.ts
  • packages/tempo/test/issues/issue-fixes.test.ts
✅ Files skipped from review due to trivial changes (7)
  • packages/tempo/doc/tempo.planner.md
  • packages/tempo/doc/releases/v4.x.md
  • packages/tempo/README.md
  • packages/tempo/doc/releases/v2.x.md
  • packages/tempo/doc/tempo.locale.md
  • packages/tempo/doc/tempo.benchmarks.md
  • packages/tempo/doc/lazy-evaluation-pattern.md

Comment thread packages/tempo/CHANGELOG.md Outdated
Comment thread packages/tempo/doc/installation.md Outdated
Comment thread packages/tempo/test/discrete/parse.locale.test.ts
@magmacomputing magmacomputing merged commit 53f5b77 into main Jun 16, 2026
2 checks passed
@magmacomputing magmacomputing deleted the feature/localize branch June 16, 2026 08:21
@coderabbitai coderabbitai Bot mentioned this pull request Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant