Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/generate-charts-landing-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url'

import { createElement } from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import './pin-catalog-locale'
import { catalogCases } from '@tanstack/react-charts-catalog'
import type { ComponentType } from 'react'
import type { CatalogChartProps } from '@tanstack/react-charts-catalog'
Expand Down
1 change: 1 addition & 0 deletions scripts/generate-charts-landing-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'

import './pin-catalog-locale'
import { catalogCases } from '@tanstack/react-charts-catalog'

type CatalogCaseMetadata = {
Expand Down
54 changes: 54 additions & 0 deletions scripts/pin-catalog-locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// The catalog case components format axis labels with `toLocaleDateString(undefined, …)`
// and `toLocaleString()`, which resolve against the machine's locale. Generating the
// landing assets on a non-English machine therefore produces different SVG text — e.g.
// `10월 6일` instead of `Oct 6` — which changes the content hash and makes
// `--check` report the committed assets as stale.
//
// `@tanstack/react-charts-catalog` already pins `en-US` on every `Intl.NumberFormat` and
// `Intl.DateTimeFormat` it constructs, so the bare prototype calls are an oversight rather
// than a deliberate choice. Until that is fixed upstream, default them here so generation
// is reproducible regardless of the machine's locale.
//
// Setting `process.env.LANG` does not work: Node resolves ICU's default locale at process
// start, before any module code runs.
//
// Imported for side effects, and must be imported before the catalog case components so the
// patch is in place when they render. Call sites that pass an explicit locale keep it.

const GENERATION_LOCALE = 'en-US'

const originalToLocaleDateString = Date.prototype.toLocaleDateString
Date.prototype.toLocaleDateString = function toLocaleDateString(
locales?: Intl.LocalesArgument,
options?: Intl.DateTimeFormatOptions,
) {
return originalToLocaleDateString.call(
this,
locales ?? GENERATION_LOCALE,
options,
)
Comment on lines +25 to +29

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- file outline ---\n'
ast-grep outline scripts/pin-catalog-locale.ts --view expanded || true

printf '\n--- relevant file contents ---\n'
cat -n scripts/pin-catalog-locale.ts

printf '\n--- native behavioral probe ---\n'
node - <<'JS'
const dates = [
  new Date('2026-08-20T12:34:56Z'),
  new Date('invalid date')
];
const options = {};
for (const date of dates) {
  for (const fn of ['toLocaleDateString','toLocaleTimeString','toLocaleString']) {
    const original = Date.prototype[fn] || Object.getPrototypeOf(new Date())?.[fn];
    console.log(original, fn, date.toISOString());
    for (const input of [undefined, null, 'en-US', 'invalid-locale']) {
      try {
        const result = original.call(date, input, options);
        console.log(`${fn}(${JSON.stringify(input)}) -> ${result}`);
      } catch (error) {
        console.log(`${fn}(${JSON.stringify(input)}) throws ${error.name}: ${error.message}`);
      }
    }
  }
}
JS

printf '\n--- search for generated default / helpers usages ---\n'
rg -n "GENERATION_LOCALE|pin-catalog|Catalog|locale" scripts package.json -S || true

Repository: TanStack/tanstack.com

Length of output: 250


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- file outline ---'
ast-grep outline scripts/pin-catalog-locale.ts --view expanded || true

printf '%s\n' ''
printf '%s\n' '--- relevant file contents ---'
cat -n scripts/pin-catalog-locale.ts

printf '%s\n' ''
printf '%s\n' '--- native behavioral probe ---'
node - <<'JS'
const dates = [new Date('2026-08-20T12:34:56Z'), new Date('invalid date')];
const options = {};
for (const date of dates) {
  for (const fn of ['toLocaleDateString','toLocaleTimeString','toLocaleString']) {
    const dateProto = Object.getPrototypeOf(new Date());
    const original = dateProto[fn];
    console.log(dateProto, fn, date.toISOString());
    for (const input of [undefined, null, 'en-US', 'invalid-locale']) {
      try {
        const result = original.call(date, input, options);
        console.log(`${fn}(${JSON.stringify(input)}) -> ${result}`);
      } catch (error) {
        console.log(`${fn}(${JSON.stringify(input)}) throws ${error.name}: ${error.message}`);
      }
    }
  }
}
JS

printf '%s\n' ''
printf '%s\n' '--- search for generated default / helpers usages ---'
rg -n "GENERATION_LOCALE|pin-catalog|Catalog|locale" scripts package.json package-lock.json bun.lockb pnpm-lock.yaml yarn.lock -S || true

Repository: TanStack/tanstack.com

Length of output: 4352


Preserve explicit invalid locale values.

locales ?? GENERATION_LOCALE treats null as omitted and formats it as en-US, while the native methods throw. Use locales === undefined ? GENERATION_LOCALE : locales in all three wrappers so only omitted locale arguments receive the generation default.

🤖 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 `@scripts/pin-catalog-locale.ts` around lines 25 - 29, Update all three locale
wrapper methods in scripts/pin-catalog-locale.ts to default only when locales is
undefined, preserving explicit null and other invalid values for native
validation. Replace the nullish fallback in each originalToLocaleDateString call
with an undefined-only conditional while keeping the existing GENERATION_LOCALE
default and call flow unchanged.

}

const originalDateToLocaleString = Date.prototype.toLocaleString
Date.prototype.toLocaleString = function toLocaleString(
locales?: Intl.LocalesArgument,
options?: Intl.DateTimeFormatOptions,
) {
return originalDateToLocaleString.call(
this,
locales ?? GENERATION_LOCALE,
options,
)
}

const originalNumberToLocaleString = Number.prototype.toLocaleString
Number.prototype.toLocaleString = function toLocaleString(
locales?: Intl.LocalesArgument,
options?: Intl.NumberFormatOptions,
) {
return originalNumberToLocaleString.call(
this,
locales ?? GENERATION_LOCALE,
options,
)
}
Loading