Files
scriptc/packages/runtime-pack-common/scripts/verify.mjs
T
Chris Tate 7329f07d36 Match V8's default locale and calendar in the ICU formatters, and build Intl programs without Zig from the runtime pack
- scr_intl.c resolves the default locale as V8 does: ICU's POSIX locale
  (LC_ALL=C, C.UTF-8, POSIX) becomes en-US, so numbers keep their grouping
  separators, and other defaults round-trip through their BCP 47 tag. The
  number formatter, the date pattern generator, the date formatter and the
  default word segmenter use that locale.
- The date formatter moves the Gregorian calendar's Julian cutover to the
  start of ECMAScript time, so dates before October 1582 print their
  proleptic Gregorian fields, as in Node.
- icu.numFormatDefault, icu.dateLocaleString and icu.dateLocaleTimeString
  are in the may-throw set: a missing ICU data file throws an Error into the
  surrounding catch.
- `x.toLocaleString(undefined)` reads the receiver before the argument runs.
- The linux-x64-gnu runtime pack ships the ICU headers scr_intl.c includes
  beside its ICU archive (manifest `headers`, verified like the other
  artifacts). The native compiler's sanitized build compiles scr_intl.c
  against them and refuses with SC3003 when they are missing or changed.
  The C-source path (sanitized builds) links the pack's ICU archive and
  uses those headers, instead of building ICU with Zig's C++ driver.
- The macOS pack omits scr_intl.c, scr_intl.h declares ScrDyn, and the
  library-mode teachings test uses a locale argument, which still refuses
  with SC2020.

Corpus programs pin the C and C.UTF-8 locales, pre-1582 dates and the
receiver order against Node. intl-missing-data.test.ts covers the throw.
sanitizer.test.ts covers the header lookup.
2026-10-29 02:42:35 -05:00

41 lines
1.5 KiB
JavaScript

#!/usr/bin/env node
import { createHash } from "node:crypto";
import { access, readFile } from "node:fs/promises";
import { join } from "node:path";
const root = process.env.SCRIPTC_RUNTIME_PACK_ROOT;
if (!root) throw new Error("runtime-pack verification requires package wrapper configuration");
const manifest = JSON.parse(await readFile(join(root, "runtime-pack.json"), "utf8"));
const packageManifest = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
if (
manifest.schema !== "scriptc.runtime-pack.v1" ||
manifest.format !== 1 ||
manifest.package !== packageManifest.name ||
manifest.version !== packageManifest.version
)
throw new Error("runtime pack identity does not match package.json");
const artifacts = [
...Object.values(manifest.flavors).flatMap((flavor) =>
flavor.runtime_units.flatMap((unit) =>
unit.variants.flatMap((variant) =>
variant.bitcode ? [variant, variant.bitcode] : [variant],
),
),
),
...manifest.archives,
...(manifest.data ?? []),
...(manifest.headers ?? []),
];
for (const artifact of artifacts) {
const bytes = await readFile(join(root, artifact.path));
if (
bytes.length !== artifact.size ||
createHash("sha256").update(bytes).digest("hex") !== artifact.sha256
)
throw new Error(`runtime pack hash mismatch: ${artifact.path}`);
}
for (const license of manifest.licenses) await access(join(root, license.path));
process.stdout.write(
`verified ${manifest.package}@${manifest.version}: ${artifacts.length} artifacts\n`,
);