Prerequisites
- JDK 17 or newer
- Node.js 22 or newer, for the Scala.js rows
- An LLVM toolchain providing
clang, for the Scala Native rows - The CLDR submodule:
git submodule update --init data/cldr - Heap for the build JVM. Export
SBT_OPTS="-Xmx12G -Xms2G -Xss4M"before running the Scala Native row: the Scala Native linker exhausts a smaller heap while linking the larger test binaries. An out-of-memory failure leaves the incremental compiler's state inconsistent, and sbt then replays the resulting compile failure throughcleanand a deletedtargetalike; recovering needs a full compile from a source-consistent tree. The other rows run comfortably in-Xmx7G, which is what CI allots them.
Project layout
modules/
core/ world-core civil time, calendars, intervals, ratios, the scheme concept
world/ world territories, languages, scripts, locales, currencies
money/ world-money monetary amounts, commercial arithmetic, trade terms
quantity/ world-quantity measures, quantities, unit prices, tariffs
id/ world-id bank, telephone, and internet identifiers
address/ world-address postal addresses, coordinates, and geographic regions
party/ world-party names, organisations, and the parties a document addresses
text/ world-text locale-correct presentation of every world value
data/ world-data curated datasets, consumed at build time
data/ pinned upstream sources and the CLDR submodule
docs/ documentation sources
project/ the curation pipeline, the packer, and the compatibility reporter
Commands
| Command | Purpose |
|---|---|
sbt format |
apply formatting, linting, and source headers |
sbt check |
verify formatting, linting, and source headers |
sbt "world-jvm/testOnly *" |
test every JVM row |
sbt "world-js/testOnly *" |
test every Scala.js row |
sbt "world-native/testOnly *" |
test every Scala Native row |
sbt world-jvm/budgets |
measure the packed data and class files against their recorded size budgets |
sbt world-native/budgets |
the same, plus the NIR budgets, which only the Native rows produce |
sbt world-data/dataVerify |
verify every dataset's provenance, pin, and redistribution terms |
sbt world-data/dataReport |
print each dataset's row count, pin, and verified terms |
sbt world-data/curate |
regenerate the datasets from their pinned upstream releases |
sbt world-site/mdoc |
compile the documentation examples |
sbt world-jvm/compatReport |
print the MiMa and TASTy-MiMa report |
Use testOnly *, not test: test selects against the previous run's analysis and will report a passing lane having executed nothing. Confirm the executed count in the output of every lane.
A change is ready when check and all three test commands pass. The compatibility report is awareness only and never declines a change.
Code
Modules compile under -Yexplicit-nulls -Wunused:all -Wall -Wsafe-init -Werror -language:strictEquality, on both the main and test configurations. -Werror is the warning-escalation gate: -Xfatal-warnings is a deprecated alias whose own deprecation notice escalates, so it fails even a warning-free compilation.
Scalafix additionally rejects var, null, throw, return, while, asInstanceOf, isInstanceOf, default arguments, and pattern-matching val bindings.
Invisible characters never appear as literals in a source file: no-break and narrow no-break spaces, the bidirectional format controls, and the isolate marks all enter as \uXXXX escapes. They carry meaning in the presentation data and are indistinguishable from an ordinary space on screen, so a literal one survives review and corrupts silently. Visible non-ASCII glyphs - a currency symbol, a month name in its own script - stay literal, because escaping them would cost more in legibility than it buys.
Data aggregates carry no methods: behaviour lives in the companion as extensions, smart constructors, and givens. Every multi-parameter extension has a companion alias for non-curried invocation, with @targetName on the extension to keep the erased signatures apart. Errors are values from owned sealed families; a failure message names the violated constraint and keeps the offending value in a typed field. Every domain type supplies CanEqual in its companion.
Data
Curated datasets are pinned per source in data/upstream-pins.json, recording the pinned version, when it was taken, and where to check for a newer one. A scheduled workflow compares each pin against its published latest and opens an issue when a source moves. It never updates data: a pin moves through a reviewed change.
dataVerify runs before the packed tables are generated, so a dataset reaches an artefact only once its provenance and terms are verified. It also runs the correctness gates over the data itself - the phone presentation formats, for instance, are checked against the possible lengths their own territory admits.
Pull requests
Branch, make the change with tests, bring the documentation to current, then run sbt format and confirm check and the three test commands pass.