Monorepo for unit conversion libraries used by Corva. A single set of shared JSON definitions powers both the JavaScript/TypeScript and Python packages.
definitions/ Shared JSON unit definitions
js/ npm package: @corva/convert-units
py/ PyPI package: corva-unit-converter
scripts/ Build and validation scripts
| Package | Language | Registry | Install |
|---|---|---|---|
@corva/convert-units |
TypeScript/JS | npm | npm install @corva/convert-units |
corva-unit-converter |
Python | PyPI | pip install corva-unit-converter |
import {
convert,
getMeasures,
describe,
getUnit,
getUnitForPair,
listUnits,
listUnitsWithAliases,
possibilities,
toBest,
bucketMapping,
getUnitKeyByAlias,
} from '@corva/convert-units';
convert(1, 'ft', 'm'); // 0.3048
convert(100, 'C', 'F'); // 212
convert(1, 'ft', 'm', 'length'); // 0.3048
getMeasures(); // ['length', 'pressure', ...]
describe('ft'); // { abbr: 'ft', measure: 'length', ... }
getUnit('ft'); // { abbr: 'ft', measure: 'length', system: 'imperial', unit: ... }
getUnitForPair('ft', 'm'); // [{ abbr: 'ft', ... }, { abbr: 'm', ... }]
listUnits('length'); // [{ abbr: 'mm', ... }, ...]
listUnitsWithAliases('length'); // [{ abbr: 'm', aliases: ['meter', ...], ... }, ...]
possibilities('length'); // ['mm', 'cm', 'm', 'km', ...]
toBest(100000, 'mm'); // { val: 100, unit: 'm', ... }
bucketMapping; // { 'Length': ['m', 'ft', ...], ... }
getUnitKeyByAlias('meter'); // 'm'from corva_unit_converter import (
convert,
get_measures,
describe,
get_unit,
get_unit_for_pair,
list_units,
list_units_with_aliases,
possibilities,
to_best,
bucket_mapping,
get_unit_key_by_alias,
)
convert(1, 'ft', 'm') # 0.3048
convert(100, 'C', 'F') # 212.0
convert(1, 'ft', 'm', measure='length') # 0.3048
get_measures() # ['length', 'pressure', ...]
describe('ft') # {'abbr': 'ft', 'measure': 'length', ...}
get_unit('ft') # {'abbr': 'ft', 'measure': 'length', 'system': 'imperial', ...}
get_unit_for_pair('ft', 'm') # ({'abbr': 'ft', ...}, {'abbr': 'm', ...})
list_units('length') # [{'abbr': 'mm', ...}, ...]
list_units_with_aliases('length') # [{'abbr': 'm', 'aliases': ['meter', ...], ...}, ...]
possibilities('length') # ['mm', 'cm', 'm', 'km', ...]
to_best(100000, 'mm') # {'val': 100, 'unit': 'm', ...}
bucket_mapping() # {'Length': ['m', 'ft', ...], ...}
get_unit_key_by_alias('meter') # 'm'Some unit abbreviations appear in more than one measure with different anchor chains. For example, bbl exists in both volume (liquid barrel, 158.987 L) and gasVolume (gas-accounting barrel, MCF-based). When no measure is specified, the library resolves to the general-purpose measure using a fixed priority order:
| Unit(s) | Resolves to (JS) | Resolves to (Python) |
|---|---|---|
gal, bbl, m3, l, fl-oz, … |
volume |
volume |
mV |
voltage |
voltage |
% |
gasConcentration |
gasConcentration |
g |
mass (gram) |
mass (gram) |
kPa/m, psi/ft |
pressureGradient |
pressureGradient |
ppm |
partsPer |
gasConcentration |
Note
Cross-measure pairs still convert when a single measure defines both units — e.g. %→Fraction (both in proportion) and bbl→Mscf (both in gasVolume) work without an explicit measure.
Caution
ppm resolves differently in the two packages, and the scales are not the same: JS uses partsPer (1 ppm = 1 ppm, 1:1), while Python uses gasConcentration (1 ppm = 0.0001 %EMA). The same ppm conversion can return different values in JS and Python. Each package preserves its original library's behavior for backward compatibility. If your code runs in both languages, always pass an explicit measure when converting ppm.
To use a specialised measure, pass it explicitly:
// JS
convert(100, 'm3', 'bbl', 'gasVolume'); // gas-accounting barrels# Python
convert(100, 'm3', 'bbl', measure='gas_volume') # gas-accounting barrelsSee definitions/SYNC_REPORT.md for the full list of shared unit keys and the rationale behind the priority order.
- Node.js 24+ (see
.nvmrc) - Python 3.9+
- GNU Make
# JS
cd js && npm install
# Python
cd py && python3 -m venv .venv && .venv/bin/pip install -e ".[test]"make sync-defs # Copy definitions into packages (local only; CI does this automatically)
make test-js # Run JS tests
make test-py # Run Python tests
make test # Run all tests (includes sync-defs automatically)
make validate # Validate JSON definition files (also runs in CI on every PR)
make build-js # Build JS package
make build-py # Build Python package
make clean # Remove build artifacts- Edit the JSON file in
definitions/(or create a new one) - Run
make testto verify both packages (syncs definitions automatically) - The
formation_densitymeasure is an alias fordensity(handled in loader code, not in JSON)
Both packages use release-please with the linked-versions plugin. Merging to master creates a combined release PR. When merged, tags js-v* and python-v* trigger separate publish workflows to npm and PyPI.