Skip to content

fix: clone settings locale data#96

Merged
korvin89 merged 3 commits into
mainfrom
fix/clone-locale-data-functions
Jun 24, 2026
Merged

fix: clone settings locale data#96
korvin89 merged 3 commits into
mainfrom
fix/clone-locale-data-functions

Conversation

@astandrik

@astandrik astandrik commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What changed

settings.getLocaleData() now clones dayjs locale data with a small internal clone helper instead of structuredClone.

The helper keeps function values intact while still returning a detached copy for plain objects and arrays.

Why

dayjs.Ls[locale] can contain functions, for example ordinal. structuredClone cannot clone functions and throws DataCloneError in browsers and Node:

import {settings} from '@gravity-ui/date-utils';

settings.getLocaleData(); // DataCloneError in 2.7.0

This surfaced in consumers that render date field/date picker components: date format expansion calls getLocaleData(), which crashes during render.

image

Tests

  • npm test -- settings
  • npm run typecheck
  • npm run lint (passes with existing warnings)
  • npm test
  • npm run build

@astandrik astandrik marked this pull request as ready for review June 22, 2026 14:17
@astandrik astandrik requested a review from amje as a code owner June 22, 2026 14:17
Copilot AI review requested due to automatic review settings June 22, 2026 14:17
@korvin89

Copy link
Copy Markdown
Collaborator

Can you describe the use case when this is played?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes settings.getLocaleData() to safely return a detached copy of Dayjs locale data even when the locale object contains function-valued properties (e.g., ordinal), avoiding structuredClone’s DataCloneError in browsers/Node.

Changes:

  • Replaced structuredClone usage in settings.getLocaleData() with a small recursive clone helper that preserves function references.
  • Added a unit test asserting locale data is cloned (new references) while function values remain callable.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/settings/settings.ts Introduces cloneLocaleData and uses it in getLocaleData() instead of structuredClone.
src/settings/settings.test.ts Adds a test to ensure locale data cloning works when locale objects contain functions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/settings/settings.test.ts
@astandrik

astandrik commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Can you describe the use case when this is played?

We hit this when rendering date controls in a downstream app.

DateField builds sections from a localized format:
useDateFieldState -> splitFormatIntoSections -> expandFormat -> settings.getLocaleData().

In 2.7.0 getLocaleData() uses structuredClone() on the dayjs locale object. The en locale contains ordinal as a function, so structuredClone() throws DataCloneError and the React subtree crashes.

Minimal repro:

import {settings} from '@gravity-ui/date-utils';

settings.getLocaleData(); // DataCloneError in 2.7.0
image

fixed with downgrade to 2.6.1 in our project

@astandrik

Copy link
Copy Markdown
Contributor Author

Can you describe the use case when this is played?

We hit this when rendering date controls in a downstream app.

DateField builds sections from a localized format: useDateFieldState -> splitFormatIntoSections -> expandFormat -> settings.getLocaleData().

In 2.7.0 getLocaleData() uses structuredClone() on the dayjs locale object. The en locale contains ordinal as a function, so structuredClone() throws DataCloneError and the React subtree crashes.

Minimal repro:

import {settings} from '@gravity-ui/date-utils';

settings.getLocaleData(); // DataCloneError in 2.7.0
image fixed with downgrade to 2.6.1 in our project

@korvin89 fyi

Comment thread src/settings/settings.ts
import {localeLoaders} from './locales';
import type {Locale, Parser, PublicSettings, UpdateLocaleConfig} from './types';

function cloneLocaleData<T>(value: T): T {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Worth a one-line comment that this helper intentionally assumes locale data is function-or-JSON-shaped. Unlike structuredClone, it would stack-overflow on a circular reference and would flatten Date/RegExp/Map/Set to {}. None of those exist in dayjs locale objects today (only strings/numbers/arrays/plain objects/functions), so nothing to fix here — just a note so a future locale field doesn't silently get mangled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 589af2a: added a one-line note that this helper is specific to Dayjs JSON-like locale data with function fields and is not a general structuredClone replacement.

expect(settings.getLocale()).toEqual(LOCALE);
});

it('should clone locale data with function values', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This test runs against whatever locale the previous test left set (de) rather than a locale it sets itself. It passes regardless since en also has ordinal + formats, but calling settings.setLocale('en') at the start would make it self-contained and order-independent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 589af2a: added settings.setLocale('en') at the start of this test, so it is self-contained and order-independent.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@korvin89 korvin89 merged commit d83ed9a into main Jun 24, 2026
3 checks passed
@korvin89 korvin89 deleted the fix/clone-locale-data-functions branch June 24, 2026 09:05
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.

3 participants