Skip to main content

Installation

TDC targets five ecosystems — npm (Node.js / TypeScript), pip (Python), Maven (Java), NuGet (.NET) and Cargo (Rust) — all producing byte-for-byte identical output from the same config, seed, version and output mode (see Determinism & proportions).

All five implementations are complete. They share one grammar, one set of diagnostic codes, and a suite of fixtures that hold them to producing the same bytes — a gigabyte of output from the same config comes out identical in each. Each one also carries the same command line, so nothing needs another language's toolchain to run a config.

All five are published, at the same version: 0.1.7 on npm, PyPI, Maven Central, NuGet and crates.io. Equal version numbers are not a coincidence — they mean the same engine, so tdcv2 0.1.7 from any one of them answers a config the same way.

Pick your ecosystem. To try TDC without committing to a language, use the npm tab: it includes a wrapper script that runs a config without any code of your own.

Requirements: Node.js 20.0.0 or newer.

npm install -D tdcv2
npx tdcv2 demo.tdc

That is the whole installation. The common, en and USA data packs come with the package, so the example below runs without downloading anything.

To work on the engine itself instead, run it from a checkout of the repository. Build it once:

npm --workspace typescript run build

Then run any config by pointing Node at the built CLI:

node typescript/dist/cli/main.js demo.tdc

There's also a one-command wrapper at the repository root, so you don't have to remember that path:

./run demo.tdc # run any file you point it at

./run is the fastest way to see output: point it at a file and read the result in the terminal. Under the hood it calls the same CLI. The full option list — --seed, --count, --output, --locale, and the rest — lives in the CLI reference.

Verify it works

Create a file called demo.tdc. It declares two columns and one line of output. The name is picked from a list with type="text", and the age is drawn from a range with type="number":

<tdc>
<env count="3" seed="demo">
<sequence name="Name">
<gen type="text" value="Alice,Bob,Carol,David,Emma"/>
</sequence>
<sequence name="Age">
<gen type="number" value="18..65"/>
</sequence>
</env>

<block>
<line>
<data>${{Name}}, age ${{Age}}</data>
</line>
</block>
</tdc>

Run it with whichever command your install gave you. Three ecosystems put tdcv2 on your PATH from the same package that carries the library; Maven and NuGet have no equivalent of npm's bin, so for those the command line is a second artefact:

Installed withThe command
Node.jsnpx tdcv2 demo.tdc
Pythontdcv2 demo.tdc
Rusttdcv2 demo.tdc, after cargo install tdcv2
C#tdcv2 demo.tdc, after dotnet tool install --global Tdcv2.Cli
Javajava -jar tdcv2-0.1.7-cli.jar demo.tdc — the cli classifier of the library's own coordinates

From the repository root, ./run demo.tdc is the shortest of them all.

tdcv2 demo.tdc
Emma, age 59
David, age 18
Carol, age 53
info

The exact names and numbers are illustrative — they can differ between core versions. What matters is that seed="demo" makes the run reproducible: the same config with the same seed gives you the same output every time.

If you get three lines of Name, age N, the install works. Run it a second time to confirm — the three rows come back identical. Then override the row count and the seed from the command line, without touching the file:

tdcv2 demo.tdc --count 20 --seed alt

Or skip the config entirely

A config is how you describe a whole dataset. But the same install also answers a single value, the way a faker does — no file, no <env>, one call:

import { tdc } from 'tdcv2';

tdc.person.lastName(); // Jones
tdc.person.male.firstName(); // Robert
tdc.common.finance.iban(); // DE62299399441396459682
tdc.country.usa.docs.ssn(); // 699209702 — with its real check digits
tdc.lang.ru.person.lastName(); // after `tdcv2 pack add ru`

Both routes read the same data packs, so the surname in a one-line call and the surname in a million-row config come from one list. Which one you want depends on whether the values have to agree with each other: a config is what ties a city to its country and holds a share to exactly 30%, and a single call ties nothing to anything.

The one-value API has the whole surface — .many(n), seed(), locale(), and how to reach a specific pack in each language.

The values here come from a seed

Each of the five is random per process on its own, the way a faker is. The values in the comments are what the seed demo draws, so tdc.seed('demo')Quick.seeded("demo") in Java and Rust — reproduces them exactly.

Install data packs (optional)

Names, cities, states, companies, and other value lists ship as data packs, separately from the engine, so updating the library never overwrites your data. A sensible default set (the top 1000 first names, for instance) is bundled, so the example above runs without downloading anything. Larger and more specialized sets are fetched on demand.

Setting this up takes two commands, init once and pack add for whatever you need. pack list is there to show you the options:

tdcv2 init # choose where packs live and the default locale
tdcv2 pack list # see what the registry offers
tdcv2 pack add en usa # download and wire up the packs you want

tdcv2 pack list prints the catalog and marks what's already installed:

tdcv2 pack list
Available data packs:

common ✓ installed Common (locale-agnostic) (0.0 MB)
Generators bound to neither a language nor a country: uuid,
hashes, ISBN/ISSN, GTIN/UPC/EAN, card PANs, MRZ, IPv4/IPv6/MAC,
semver, and more.

…

usa ✓ installed Usa (country) (0.0 MB)
Data specific to the USA regardless of the language it is
written in: SSN/ITIN/EIN, ZIP codes, states, street names, ABA
routing numbers, phone format, license plates.

Packs compose along independent axes — language, country, and a locale-agnostic common — so US data in English is common + en + usa. The full workflow (the config file, pack shadowing, removing packs) is covered in Installing data packs.

What's next