measurable 1.1.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -0
- package/README.md +271 -53
- package/dist/dimensions/angle.js +13 -6
- package/dist/dimensions/area.d.ts +14 -0
- package/dist/dimensions/area.js +46 -0
- package/dist/dimensions/data.d.ts +10 -0
- package/dist/dimensions/data.js +39 -0
- package/dist/dimensions/energy.d.ts +14 -0
- package/dist/dimensions/energy.js +29 -0
- package/dist/dimensions/force.js +6 -6
- package/dist/dimensions/frequency.d.ts +7 -0
- package/dist/dimensions/frequency.js +11 -0
- package/dist/dimensions/illuminance.d.ts +9 -0
- package/dist/dimensions/illuminance.js +16 -0
- package/dist/dimensions/index.d.ts +9 -0
- package/dist/dimensions/index.js +9 -0
- package/dist/dimensions/length.js +7 -7
- package/dist/dimensions/luminance.d.ts +7 -0
- package/dist/dimensions/luminance.js +13 -0
- package/dist/dimensions/luminousIntensity.d.ts +9 -0
- package/dist/dimensions/luminousIntensity.js +16 -0
- package/dist/dimensions/mass.js +13 -9
- package/dist/dimensions/power.d.ts +9 -0
- package/dist/dimensions/power.js +13 -0
- package/dist/dimensions/pressure.d.ts +14 -0
- package/dist/dimensions/pressure.js +21 -0
- package/dist/dimensions/temperature.js +9 -3
- package/dist/dimensions/time.js +19 -7
- package/dist/dimensions/volume.js +57 -24
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/lib/Dimension.d.ts +49 -14
- package/dist/lib/Dimension.js +58 -21
- package/dist/lib/MeasurementSystem.js +2 -2
- package/dist/lib/Quantity.d.ts +94 -10
- package/dist/lib/Quantity.js +92 -37
- package/dist/lib/Rational.d.ts +58 -0
- package/dist/lib/Rational.js +174 -0
- package/dist/lib/Unit.d.ts +52 -11
- package/dist/lib/Unit.js +41 -8
- package/dist/lib/prefixes.d.ts +2 -2
- package/dist/lib/prefixes.js +1 -1
- package/dist/systems/imperial.js +19 -1
- package/dist/systems/metric.js +25 -1
- package/dist/systems/usCustomary.js +19 -1
- package/dist/utils/definePrefixed.d.ts +28 -0
- package/dist/utils/definePrefixed.js +72 -0
- package/dist/utils/scaleOf.d.ts +3 -0
- package/dist/utils/scaleOf.js +6 -0
- package/package.json +13 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [3.0.0] - 2026-06-18
|
|
9
|
+
|
|
10
|
+
This release adds value **formatting**. Units now carry a `symbol` and `plural`,
|
|
11
|
+
and a `Quantity` can render itself with magnitude-aware pluralization and
|
|
12
|
+
locale-aware number formatting. Threading symbol/plural through the unit builders
|
|
13
|
+
changes their signatures, hence the major bump.
|
|
14
|
+
|
|
15
|
+
### Breaking
|
|
16
|
+
|
|
17
|
+
- **Unit builder methods take a `UnitDef` object instead of an aliases array.**
|
|
18
|
+
`Dimension.base` / `unit` / `affine` / `custom` now accept
|
|
19
|
+
`{ symbol?, plural?, aliases? }` as their final argument rather than a bare
|
|
20
|
+
`string[]` of aliases. Migrate `length.unit("inch", 0.0254, ["in", "inches"])`
|
|
21
|
+
to `length.unit("inch", 0.0254, { symbol: "in", plural: "inches" })`; plain
|
|
22
|
+
aliases still work via the `aliases` field.
|
|
23
|
+
- **`definePrefixed` takes the reference `Unit`, not a descriptor object.**
|
|
24
|
+
`definePrefixed(length, { name: "meter", symbol: "m" })` becomes
|
|
25
|
+
`definePrefixed(length, meter)` — it reads the name, symbol, and exact scale
|
|
26
|
+
straight off the unit. The `PrefixReference` type is removed.
|
|
27
|
+
- **`Unit`'s constructor options gained `symbol` / `plural`.** Only affects code
|
|
28
|
+
that calls `new Unit(...)` directly; units built through a `Dimension` are
|
|
29
|
+
unaffected.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`Unit.symbol` and `Unit.plural`** — optional, first-class descriptors. Both
|
|
34
|
+
are also registered as parse tokens, so `Quantity.parse` accepts e.g. `"5 g"`
|
|
35
|
+
and `"5 grams"`.
|
|
36
|
+
- **`Quantity.format(options?)`** — renders `"<magnitude> <label>"`. `unit`
|
|
37
|
+
selects the label: `"auto"` (default — singular `name` at ±1, otherwise
|
|
38
|
+
`plural`), `"name"`, `"plural"`, or `"symbol"`, each falling back to `name`
|
|
39
|
+
when unset. The magnitude is rendered with `toLocaleString`; pass `locale`
|
|
40
|
+
and/or `numberFormat` (`Intl.NumberFormatOptions`) for locale- and
|
|
41
|
+
precision-aware output.
|
|
42
|
+
- **`Quantity.formatParts(options?)`** — the same options as `format`, but
|
|
43
|
+
returns the rendered `{ magnitude, unit }` as separate strings for custom
|
|
44
|
+
assembly (e.g. JSX).
|
|
45
|
+
- **`definePrefixed` derives each variant's `symbol` and `plural`** from the
|
|
46
|
+
reference unit (e.g. `meter` → `kilometer` / `km`), keeping the prefixed scale
|
|
47
|
+
exact via rational arithmetic.
|
|
48
|
+
- New exported types: `UnitDef`, `FormatOptions`, `FormattedParts`,
|
|
49
|
+
`BaseUnitOptions`, `UnitConversionOptions`, and `UnitOptions`.
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- Added `assert-never` as a (small) runtime dependency, used for exhaustiveness
|
|
54
|
+
checking in formatting.
|
|
55
|
+
|
|
56
|
+
## [2.0.0] - 2026-06-18
|
|
57
|
+
|
|
58
|
+
This release makes conversions and quantity arithmetic **exact**. Magnitudes and
|
|
59
|
+
unit transforms are represented as exact rationals internally and only collapse
|
|
60
|
+
to a `number` at the edge, so `foot → inch` is exactly `12` (not
|
|
61
|
+
`12.000000000000002`) and chains and round trips no longer accumulate drift.
|
|
62
|
+
|
|
63
|
+
### Breaking
|
|
64
|
+
|
|
65
|
+
- **`Quantity.magnitude` is now a read-only getter** derived from the new
|
|
66
|
+
`Quantity.rational`, rather than a writable field. Assigning to
|
|
67
|
+
`quantity.magnitude` no longer works.
|
|
68
|
+
- **`Quantity` construction rejects non-finite magnitudes.**
|
|
69
|
+
`new Quantity(Infinity, unit)` (or `NaN`) now throws instead of being accepted.
|
|
70
|
+
- **`Unit.toBase` / `Unit.fromBase` are methods, not function-valued fields.**
|
|
71
|
+
Calling `unit.toBase(x)` is unchanged; holding an unbound reference such as
|
|
72
|
+
`const f = unit.toBase` no longer works.
|
|
73
|
+
- **`Unit`'s constructor options changed shape** to a discriminated union
|
|
74
|
+
(`{ linear }` vs `{ toBase, fromBase }`). Only affects code that calls
|
|
75
|
+
`new Unit(...)` directly; the `Dimension` builder methods are unaffected.
|
|
76
|
+
- **Conversion results changed value.** Outputs are now exact, so values that
|
|
77
|
+
previously carried floating-point error differ (e.g. `12.000000000000002` is
|
|
78
|
+
now `12`). `Quantity` equality and comparison are now exact rational
|
|
79
|
+
comparisons rather than float `===`, so quantities that are mathematically
|
|
80
|
+
equal compare equal even across a conversion that previously drifted.
|
|
81
|
+
- **Requires Node >= 14** (declared via `engines`); the library now uses `bigint`.
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
|
|
85
|
+
- **`Rational`** — an exact rational number (`bigint` numerator/denominator),
|
|
86
|
+
exported from the package root. Supports `plus`/`minus`/`times`/`dividedBy`
|
|
87
|
+
(with `add`/`sub`/`mul`/`div` aliases), `negate`/`abs`, `equals`/`eq`,
|
|
88
|
+
`compare`, `sign`, `toNumber`, and the static `Rational.from`.
|
|
89
|
+
- **`Quantity.rational`** exposes the exact magnitude; the constructor and
|
|
90
|
+
`times`/`dividedBy` now accept `number | Rational`.
|
|
91
|
+
- **`Dimension.convertRational(value, from, to)`** — exact, rational-in /
|
|
92
|
+
rational-out conversion.
|
|
93
|
+
- **`Unit.linear`** — the exact `{ scale, offset }` transform for linear and
|
|
94
|
+
affine units (`undefined` for `custom` ones).
|
|
95
|
+
- **`Dimension.unit` and `Dimension.affine` accept `number | Rational`**, so a
|
|
96
|
+
ratio a decimal cannot represent exactly (e.g. Fahrenheit's `5/9`) can be
|
|
97
|
+
given exactly.
|
|
98
|
+
- New built-in dimensions: `area`, `data`, `energy`, `frequency`,
|
|
99
|
+
`illuminance`, `luminance`, `luminousIntensity`, `power`, and `pressure`
|
|
100
|
+
(each with its SI prefix ladder where applicable).
|
|
101
|
+
- `definePrefixed`'s reference `scale` is now optional, defaulting to `1`.
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- Linear and affine conversions are now exact (`foot → inch` is `12`, `1 L → mL`
|
|
106
|
+
round trips cleanly, and so on).
|
|
107
|
+
- SI-prefixed scales are computed in rational arithmetic, fixing drifted scales
|
|
108
|
+
such as `nanowattHour` (`3600 × 1e-9`).
|
|
109
|
+
- Built-in Fahrenheit is defined with exact rationals and round-trips without
|
|
110
|
+
drift in both directions.
|
|
111
|
+
- `Rational.toNumber` stays correctly rounded at extreme magnitudes (operands
|
|
112
|
+
beyond `2^53`), where converting each operand to a double before dividing
|
|
113
|
+
would otherwise lose precision.
|
|
114
|
+
|
|
115
|
+
## [1.1.1] - 2026-06-17
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- Enable `embed-readme` so the README renders on npmjs.com.
|
|
120
|
+
|
|
121
|
+
## [1.1.0] - 2026-06-17
|
|
122
|
+
|
|
123
|
+
### Added
|
|
124
|
+
|
|
125
|
+
- SI metric prefix ladders generated across the metric dimensions.
|
|
126
|
+
- `Quantity` arithmetic — `plus` / `minus` / `times` / `dividedBy` (with
|
|
127
|
+
`add` / `sub` / `mul` / `div` aliases).
|
|
128
|
+
- `Quantity` comparison — `equals` / `notEquals` / `lessThan` / `greaterThan` /
|
|
129
|
+
`lessThanOrEqual` / `greaterThanOrEqual` (with `eq` / `ne` / `lt` / `gt` /
|
|
130
|
+
`lte` / `gte` aliases), plus `compareTo` as a sort comparator.
|
|
131
|
+
- `Quantity.ratioTo` for the dimensionless ratio between two quantities.
|
|
132
|
+
- `Quantity.abs` and the `Quantity.min` / `max` / `sum` statics.
|
|
133
|
+
- `clamp` as an instance method bounding a quantity to a range.
|
|
134
|
+
- `Quantity.toString`.
|
|
135
|
+
- `Quantity.isZero` / `isPositive` / `isNegative` predicates and `round`.
|
|
136
|
+
|
|
137
|
+
## [1.0.0] - 2026-06-16
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
|
|
141
|
+
- Initial release: the core conversion engine (`Dimension`, `Unit`, `Quantity`,
|
|
142
|
+
`MeasurementSystem`), string parsing via `Quantity.parse`, and the first set
|
|
143
|
+
of built-in dimensions and measurement systems.
|
|
144
|
+
|
|
145
|
+
[3.0.0]: https://github.com/mhuggins/measurable/compare/v2.0.0...v3.0.0
|
|
146
|
+
[2.0.0]: https://github.com/mhuggins/measurable/compare/v1.1.1...v2.0.0
|
|
147
|
+
[1.1.1]: https://github.com/mhuggins/measurable/compare/v1.1.0...v1.1.1
|
|
148
|
+
[1.1.0]: https://github.com/mhuggins/measurable/compare/v1.0.0...v1.1.0
|
|
149
|
+
[1.0.0]: https://github.com/mhuggins/measurable/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
Convert between units of measurement, with batteries-included common units and
|
|
4
4
|
first-class support for defining your own.
|
|
5
5
|
|
|
6
|
-
- **
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
- **Exact, no drift** — magnitudes are held as exact rational numbers and
|
|
7
|
+
conversions run in rational arithmetic, collapsing to a float only when you
|
|
8
|
+
read `.magnitude`. So `foot → inch` is exactly `12` (not `12.000000000000002`),
|
|
9
|
+
and chains and round trips like `liter → gallon → liter` come back to exactly
|
|
10
|
+
what you started with.
|
|
11
|
+
- **No redundant factors** — each unit defines a single transform to its
|
|
12
|
+
dimension's base unit; reverse conversions are derived, never stored, so they
|
|
13
|
+
can't fall out of sync.
|
|
9
14
|
- **Free chaining** — any unit converts to any other in the same dimension
|
|
10
15
|
(e.g. `mile → inch`) without you defining every pair.
|
|
11
16
|
- **Affine units** — temperature scales (°C/°F/K) and anything else needing an
|
|
@@ -26,7 +31,7 @@ The package is split into three import paths so the core stays lean:
|
|
|
26
31
|
|
|
27
32
|
| Import | What you get |
|
|
28
33
|
| -------------------------- | ------------------------------------------------------------------------- |
|
|
29
|
-
| `measurable` | The building blocks: `Quantity`, `Dimension`, `MeasurementSystem`, `Unit`, errors |
|
|
34
|
+
| `measurable` | The building blocks: `Quantity`, `Dimension`, `MeasurementSystem`, `Unit`, `Rational`, errors |
|
|
30
35
|
| `measurable/dimensions` | Predefined dimensions and their units (`length`, `meter`, `volume`, …) |
|
|
31
36
|
| `measurable/systems` | Predefined measurement systems (`metric`, `imperial`, `usCustomary`) |
|
|
32
37
|
|
|
@@ -34,7 +39,7 @@ The package is split into three import paths so the core stays lean:
|
|
|
34
39
|
|
|
35
40
|
```ts
|
|
36
41
|
import { Quantity } from "measurable";
|
|
37
|
-
import { meter, mile, celsius, fahrenheit } from "measurable/dimensions";
|
|
42
|
+
import { meter, mile, foot, inch, celsius, fahrenheit } from "measurable/dimensions";
|
|
38
43
|
|
|
39
44
|
// Convert: `.to()` returns a Quantity, `.in()` returns a raw number.
|
|
40
45
|
new Quantity(5, mile).to(meter).magnitude; // 8046.72
|
|
@@ -42,6 +47,10 @@ new Quantity(5, mile).in(meter); // 8046.72
|
|
|
42
47
|
|
|
43
48
|
// Affine scales work the same way.
|
|
44
49
|
new Quantity(100, celsius).in(fahrenheit); // 212
|
|
50
|
+
|
|
51
|
+
// Conversions are exact: magnitudes are rationals under the hood.
|
|
52
|
+
new Quantity(1, foot).in(inch); // 12 (not 12.000000000000002)
|
|
53
|
+
new Quantity(1, foot).to(inch).to(foot).magnitude; // 1 (exact round trip)
|
|
45
54
|
```
|
|
46
55
|
|
|
47
56
|
## Concepts
|
|
@@ -49,35 +58,110 @@ new Quantity(100, celsius).in(fahrenheit); // 212
|
|
|
49
58
|
- **`Dimension`** — a kind of measurable quantity (length, volume, mass, …). It
|
|
50
59
|
owns a canonical **base unit** and is where all conversion happens. A unit
|
|
51
60
|
belongs to exactly one dimension.
|
|
52
|
-
- **`Unit`** — a name plus a transform
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
- **`Unit`** — a name plus a transform into its dimension's base unit: an exact
|
|
62
|
+
rational `scale`/`offset` for linear and affine units, or an arbitrary
|
|
63
|
+
function pair for `custom` ones. Created through a dimension's builder methods.
|
|
64
|
+
- **`Quantity`** — a magnitude paired with a unit (e.g. `5 kilometer`). The
|
|
65
|
+
magnitude is held as an exact **`Rational`**; `.magnitude` reads it as a
|
|
66
|
+
`number`.
|
|
67
|
+
- **`Rational`** — an exact rational number (`n / d` over `bigint`s) used for the
|
|
68
|
+
lossless arithmetic above. You rarely construct one directly, but can pass one
|
|
69
|
+
anywhere a magnitude or scale is expected.
|
|
55
70
|
- **`MeasurementSystem`** — a cross-dimension tag (metric/imperial/…). A unit can
|
|
56
71
|
belong to many; membership is optional and never affects whether a conversion
|
|
57
72
|
is allowed.
|
|
58
73
|
|
|
74
|
+
## Exact arithmetic
|
|
75
|
+
|
|
76
|
+
A linear conversion is inherently rational — a foot is exactly `3048/10000` m and
|
|
77
|
+
an inch exactly `254/10000` m, so a foot is exactly `12` inches. Storing those
|
|
78
|
+
ratios as binary floats and routing values through the base unit loses that
|
|
79
|
+
(`1 foot → inch` would give `12.000000000000002`).
|
|
80
|
+
|
|
81
|
+
Instead, each `Quantity` keeps its magnitude as an exact `Rational`, and
|
|
82
|
+
conversions/arithmetic run in rational arithmetic, collapsing to a `number` only
|
|
83
|
+
when you read `.magnitude` (or call `.in()`). Because nothing is collapsed
|
|
84
|
+
mid-chain, conversions compose without accumulating drift:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { Quantity } from "measurable";
|
|
88
|
+
import { liter, usGallon } from "measurable/dimensions";
|
|
89
|
+
|
|
90
|
+
// A round trip through an awkward ratio still lands exactly on 7.
|
|
91
|
+
new Quantity(7, liter).to(usGallon).to(liter).magnitude; // 7
|
|
92
|
+
|
|
93
|
+
// .rational exposes the underlying exact value (always in lowest terms).
|
|
94
|
+
new Quantity(7, liter).to(usGallon).rational; // Rational 125000000/67596639
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This is exact for linear and affine units. A conversion that passes through a
|
|
98
|
+
non-linear `custom` unit (e.g. a logarithmic scale) necessarily uses floating
|
|
99
|
+
point and recaptures the result as a rational, so it is best-effort there.
|
|
100
|
+
|
|
59
101
|
## Built-in dimensions
|
|
60
102
|
|
|
61
103
|
Import any dimension or unit from `measurable/dimensions`:
|
|
62
104
|
|
|
63
|
-
| Dimension
|
|
64
|
-
|
|
|
65
|
-
| `length`
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
105
|
+
| Dimension | Base | Units (a selection) |
|
|
106
|
+
| -------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
107
|
+
| `length` | `meter` | `kilometer`, `centimeter`, `millimeter`, `inch`, `foot`, `yard`, `mile` |
|
|
108
|
+
| `area` | `squareMeter` | `squareKilometer`, `hectare`, `are`, `squareInch`, `squareFoot`, `squareYard`, `acre`, `squareMile` |
|
|
109
|
+
| `volume` | `liter` | `milliliter`, `us*`/`imperial*` `Gallon`/`Quart`/`Pint`/`Gill`/`FluidOunce`, `cup`, `tablespoon`, `teaspoon` |
|
|
110
|
+
| `mass` | `gram` | `kilogram`, `milligram`, `tonne`, `pound`, `ounce`, `stone`, `shortTon`, `longTon` |
|
|
111
|
+
| `time` | `second` | `millisecond`, `minute`, `hour`, `day`, `week` |
|
|
112
|
+
| `temperature` | `kelvin` | `celsius`, `fahrenheit` |
|
|
113
|
+
| `angle` | `radian` | `degree`, `gradian`, `turn` |
|
|
114
|
+
| `force` | `newton` | `kilonewton`, `dyne`, `poundForce`, `kilogramForce` |
|
|
115
|
+
| `energy` | `joule` | `kilojoule`, `wattHour`, `kilowattHour`, `calorie`, `kilocalorie`, `britishThermalUnit` |
|
|
116
|
+
| `power` | `watt` | `kilowatt`, `megawatt`, `horsepower`, `metricHorsepower` |
|
|
117
|
+
| `pressure` | `pascal` | `kilopascal`, `bar`, `millibar`, `atmosphere`, `torr`, `psi`, `inchOfMercury`, `inchOfWater` |
|
|
118
|
+
| `frequency` | `hertz` | `kilohertz`, `megahertz`, `gigahertz`, `terahertz` |
|
|
119
|
+
| `data` | `bit` | `byte`, `nibble`, `kilobyte`…`petabyte` (SI), `kibibyte`…`pebibyte` (IEC) |
|
|
120
|
+
| `illuminance` | `lux` | `kilolux`, `millilux`, `footCandle`, `phot` |
|
|
121
|
+
| `luminance` | `candelaPerSquareMeter` | `nit`, `stilb` |
|
|
122
|
+
| `luminousIntensity` | `candela` | `kilocandela`, `millicandela`, `candlepower`, `hefnerkerze` |
|
|
72
123
|
|
|
73
124
|
The metric units carry the **full SI prefix ladder** (yotta → yocto), generated for
|
|
74
|
-
you: `length`, `mass`, `volume`,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`millisecond`, `microradian`).
|
|
78
|
-
`
|
|
79
|
-
|
|
80
|
-
|
|
125
|
+
you: the SI-based dimensions (`length`, `mass`, `volume`, `force`, `energy`, `power`,
|
|
126
|
+
`pressure`, `frequency`, `illuminance`, `luminousIntensity`) get every prefix (so
|
|
127
|
+
`kilogram` itself is just the kilo-prefixed gram), while `time` and `angle` get the
|
|
128
|
+
fractional prefixes only (e.g. `millisecond`, `microradian`). Every generated rung
|
|
129
|
+
parses from its symbol (`dm`, `hm`, `Mg`, `kL`, `ns`, `GHz`, `kPa`, and `µm`/`um` for
|
|
130
|
+
micro) and converts like any other unit. `data` additionally carries the **IEC binary**
|
|
131
|
+
multiples (`kibibyte`, `mebibyte`, … = 1024-based) alongside the SI decimal ones
|
|
132
|
+
(`kilobyte`, … = 1000-based). You can apply the same ladder to your own dimensions with
|
|
133
|
+
`definePrefixed` (see below).
|
|
134
|
+
|
|
135
|
+
### Prefixed unit exports
|
|
136
|
+
|
|
137
|
+
Each prefixed dimension exports a **record** holding the _complete_ generated ladder
|
|
138
|
+
keyed by name (the return value of `definePrefixed`), plus a **curated subset of those
|
|
139
|
+
same units as individual named exports** for convenience. Reach any rung that isn't
|
|
140
|
+
exported individually through the record — e.g. `metricLength.gigameter`,
|
|
141
|
+
`metricMass.exagram` — or by parsing its symbol.
|
|
142
|
+
|
|
143
|
+
| Dimension | Record export(s) | Individually exported units |
|
|
144
|
+
| ------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
145
|
+
| `length` | `metricLength` | `kilometer`, `hectometer`, `decameter`, `decimeter`, `centimeter`, `millimeter`, `micrometer`, `nanometer` |
|
|
146
|
+
| `mass` | `metricMass` | `kilogram`, `megagram`, `hectogram`, `decagram`, `decigram`, `centigram`, `milligram`, `microgram`, `nanogram` |
|
|
147
|
+
| `volume` | `metricVolume` | `kiloliter`, `hectoliter`, `decaliter`, `deciliter`, `centiliter`, `milliliter` |
|
|
148
|
+
| `time` | `metricTime` | `millisecond`, `microsecond`, `nanosecond`, `picosecond` |
|
|
149
|
+
| `angle` | `metricAngle` | `milliradian`, `microradian` |
|
|
150
|
+
| `force` | `metricForce` | `meganewton`, `kilonewton`, `millinewton`, `micronewton` |
|
|
151
|
+
| `energy` | `metricEnergy`, `metricWattHour` | `kilojoule`, `megajoule`, `gigajoule`, `millijoule`; `kilowattHour`, `megawattHour`, `gigawattHour` |
|
|
152
|
+
| `power` | `metricPower` | `kilowatt`, `megawatt`, `gigawatt`, `terawatt`, `milliwatt` |
|
|
153
|
+
| `pressure` | `metricPressure` | `kilopascal`, `hectopascal`, `megapascal`, `gigapascal` |
|
|
154
|
+
| `frequency` | `metricFrequency` | `kilohertz`, `megahertz`, `gigahertz`, `terahertz`, `petahertz`, `millihertz` |
|
|
155
|
+
| `illuminance` | `metricIlluminance` | `kilolux`, `millilux`, `microlux` |
|
|
156
|
+
| `luminousIntensity` | `metricLuminousIntensity` | `kilocandela`, `millicandela`, `microcandela` |
|
|
157
|
+
| `data` | `dataMultiples` | `kilobit`/`kilobyte` … `petabit`/`petabyte` (SI), `kibibit`/`kibibyte` … `pebibit`/`pebibyte` (IEC) |
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { metricLength, kilometer } from "measurable/dimensions";
|
|
161
|
+
|
|
162
|
+
kilometer === metricLength.kilometer; // true — the named export is the same unit
|
|
163
|
+
metricLength.gigameter; // a rung not exported by name, reached via the record
|
|
164
|
+
```
|
|
81
165
|
|
|
82
166
|
## Built-in measurement systems
|
|
83
167
|
|
|
@@ -92,6 +176,13 @@ usCustomary.has(foot); // true
|
|
|
92
176
|
metric.has(foot); // false
|
|
93
177
|
```
|
|
94
178
|
|
|
179
|
+
Membership spans every dimension: SI units (`squareMeter`, `pascal`, `watt`, `joule`,
|
|
180
|
+
`hertz`, `lux`, `candela`, and their prefix ladders) are tagged into `metric`, while the
|
|
181
|
+
customary ones (`squareFoot`, `acre`, `psi`, `horsepower`, `britishThermalUnit`,
|
|
182
|
+
`footCandle`, `candlepower`) belong to both `imperial` and `usCustomary`. Units tied to
|
|
183
|
+
no real-world standard (e.g. `atmosphere`, `torr`, and the `data` multiples) stay
|
|
184
|
+
untagged — they still convert, they just won't appear under any system.
|
|
185
|
+
|
|
95
186
|
### Listing units in a system
|
|
96
187
|
|
|
97
188
|
```ts
|
|
@@ -115,9 +206,65 @@ metric.express(new Quantity(5000, meter)); // Quantity(5, kilometer)
|
|
|
115
206
|
imperial.express(new Quantity(5000, meter)); // Quantity(3.107…, mile)
|
|
116
207
|
```
|
|
117
208
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
209
|
+
## Formatting output
|
|
210
|
+
|
|
211
|
+
Each unit carries a canonical `symbol` (`"g"`, `"km"`, `"°C"`) and `plural`
|
|
212
|
+
(`"grams"`, `"kilometers"`) alongside its `name`, so a `Quantity` can be rendered the
|
|
213
|
+
way you want:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { Quantity } from "measurable";
|
|
217
|
+
import { gram } from "measurable/dimensions";
|
|
218
|
+
|
|
219
|
+
new Quantity(5, gram).toString(); // "5 gram" (always the bare name)
|
|
220
|
+
new Quantity(5, gram).format(); // "5 grams" (magnitude-aware)
|
|
221
|
+
new Quantity(1, gram).format(); // "1 gram" (singular at ±1)
|
|
222
|
+
new Quantity(5, gram).format({ unit: "symbol" }); // "5 g"
|
|
223
|
+
new Quantity(5, gram).format({ unit: "name" }); // "5 gram"
|
|
224
|
+
new Quantity(5, gram).format({ unit: "plural" }); // "5 grams"
|
|
225
|
+
|
|
226
|
+
// Localize the magnitude with locale / numberFormat (passed to toLocaleString):
|
|
227
|
+
new Quantity(1234.5, meter).format({ locale: "de-DE" }); // "1.234,5 meters"
|
|
228
|
+
new Quantity(1.23456, meter).format({ numberFormat: { maximumFractionDigits: 2 } }); // "1.23 meters"
|
|
229
|
+
new Quantity(1234.5, kilometer).format({ locale: "de-DE", unit: "symbol" }); // "1.234,5 km"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`toString()` is intentionally stable (`"<magnitude> <name>"`). `format(options?)` is the
|
|
233
|
+
flexible one: `unit` defaults to `"auto"` (singular `name` at ±1, otherwise `plural`) and
|
|
234
|
+
accepts `"name"`, `"plural"`, or `"symbol"`. When a unit has no `symbol`/`plural`, those
|
|
235
|
+
modes fall back to its `name`.
|
|
236
|
+
|
|
237
|
+
The magnitude is rendered with `Number.prototype.toLocaleString`. Pass `locale` (a BCP 47
|
|
238
|
+
locale or array) and/or `numberFormat` (`Intl.NumberFormatOptions` — precision via
|
|
239
|
+
`maximumFractionDigits`, grouping, `style`, …) to control it; with neither set, the
|
|
240
|
+
runtime's default locale is used. Use `round(decimals)` to trim the magnitude first
|
|
241
|
+
(`new Quantity(1.6213, mile).round(2)` → `1.62 mile`).
|
|
242
|
+
|
|
243
|
+
When a single string won't do — e.g. styling the magnitude in a React component — use
|
|
244
|
+
`formatParts(options?)`, which takes the same options but returns the rendered
|
|
245
|
+
`{ magnitude, unit }` as separate strings for you to assemble:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
const { magnitude, unit } = new Quantity(1234.5, kilometer).formatParts({ locale: "de-DE" });
|
|
249
|
+
// { magnitude: "1.234,5", unit: "kilometers" }
|
|
250
|
+
return <><b>{magnitude}</b> {unit}</>;
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Internationalization
|
|
254
|
+
|
|
255
|
+
`format()` localizes the **magnitude** (via `locale`/`numberFormat`), but the **label** it
|
|
256
|
+
appends — `symbol`/`plural` — is **English/canonical** convenience data, not a localization
|
|
257
|
+
system: a single plural string can't model languages with several plural forms, and the
|
|
258
|
+
names themselves are English. For a fully localized label, delegate to `Intl.NumberFormat`,
|
|
259
|
+
whose `style: "unit"` localizes **and** pluralizes a curated set of units for you:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
const q = new Quantity(5, kilometer);
|
|
263
|
+
new Intl.NumberFormat("de", { style: "unit", unit: "kilometer" }).format(q.magnitude);
|
|
264
|
+
// "5 Kilometer"
|
|
265
|
+
new Intl.NumberFormat("fr", { style: "unit", unit: "kilometer", unitDisplay: "short" })
|
|
266
|
+
.format(q.magnitude); // "5 km"
|
|
267
|
+
```
|
|
121
268
|
|
|
122
269
|
## Parsing strings
|
|
123
270
|
|
|
@@ -163,9 +310,10 @@ new Quantity(1, shortTon).in(tonne); // 0.90718474
|
|
|
163
310
|
|
|
164
311
|
Quantities can be combined. `plus`/`minus` take another `Quantity` (converted into
|
|
165
312
|
the receiver's unit first, so the operands may use different units of the same
|
|
166
|
-
dimension); `times`/`dividedBy` apply a dimensionless scalar
|
|
167
|
-
transform the magnitude. All return a **new**
|
|
168
|
-
leave the operands untouched.
|
|
313
|
+
dimension); `times`/`dividedBy` apply a dimensionless scalar (a `number` or a
|
|
314
|
+
`Rational`), and `negate`/`abs` transform the magnitude. All return a **new**
|
|
315
|
+
`Quantity` in the receiver's unit and leave the operands untouched. Like
|
|
316
|
+
conversions, the arithmetic is exact — `q.times(3).dividedBy(3)` returns `q`.
|
|
169
317
|
|
|
170
318
|
```ts
|
|
171
319
|
import { Quantity } from "measurable";
|
|
@@ -220,8 +368,11 @@ new Quantity(1, kilometer).greaterThan(new Quantity(1, meter)); // true
|
|
|
220
368
|
|
|
221
369
|
Short aliases: **`eq`** (`equals`), **`ne`** (`notEquals`), **`lt`** (`lessThan`),
|
|
222
370
|
**`gt`** (`greaterThan`), **`lte`** (`lessThanOrEqual`), **`gte`**
|
|
223
|
-
(`greaterThanOrEqual`).
|
|
224
|
-
|
|
371
|
+
(`greaterThanOrEqual`). Comparison is exact rational comparison, so quantities
|
|
372
|
+
that are mathematically equal compare equal even when reaching them involved a
|
|
373
|
+
conversion that would have drifted in floating point — e.g.
|
|
374
|
+
`new Quantity(7, liter).to(usGallon).to(liter).equals(new Quantity(7, liter))` is
|
|
375
|
+
`true`.
|
|
225
376
|
|
|
226
377
|
`compareTo(other)` returns `-1`, `0`, or `1`, suitable as an `Array#sort`
|
|
227
378
|
comparator: `quantities.sort((a, b) => a.compareTo(b))`.
|
|
@@ -248,26 +399,55 @@ b.clamp(a, new Quantity(2, kilometer)); // b bounded to [a, 2 km], in b's unit
|
|
|
248
399
|
## Defining your own units
|
|
249
400
|
|
|
250
401
|
Create a `Dimension` and add units through its builder methods. `scale` is how
|
|
251
|
-
many base units make up one of the unit being defined.
|
|
402
|
+
many base units make up one of the unit being defined. The optional final argument
|
|
403
|
+
is a definition object — `{ symbol?, plural?, aliases? }` — whose `symbol` and
|
|
404
|
+
`plural` feed `format()` and, like `aliases`, are also registered for parsing.
|
|
252
405
|
|
|
253
406
|
```ts
|
|
254
407
|
import { Dimension, Quantity } from "measurable";
|
|
255
408
|
|
|
256
409
|
const data = new Dimension("data");
|
|
257
|
-
const byte = data.base("byte",
|
|
258
|
-
const kilobyte = data.unit("kilobyte", 1024,
|
|
259
|
-
const megabyte = data.unit("megabyte", 1024 ** 2,
|
|
410
|
+
const byte = data.base("byte", { symbol: "B", plural: "bytes" }); // base unit (identity)
|
|
411
|
+
const kilobyte = data.unit("kilobyte", 1024, { symbol: "KB", plural: "kilobytes" });
|
|
412
|
+
const megabyte = data.unit("megabyte", 1024 ** 2, { symbol: "MB", plural: "megabytes" });
|
|
413
|
+
|
|
414
|
+
new Quantity(2, megabyte).in(kilobyte); // 2048
|
|
415
|
+
new Quantity(2, megabyte).format(); // "2 megabytes"
|
|
416
|
+
new Quantity(2, megabyte).format({ unit: "symbol" }); // "2 MB"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
A numeric `scale` is read as the exact decimal you wrote (`0.0254` → `254/10000`),
|
|
420
|
+
which is exact for any terminating decimal. For a ratio a decimal **can't**
|
|
421
|
+
represent exactly — e.g. `5/9` — pass a `Rational` so it stays exact:
|
|
260
422
|
|
|
261
|
-
|
|
423
|
+
```ts
|
|
424
|
+
import { Dimension, Rational } from "measurable";
|
|
425
|
+
|
|
426
|
+
const ratio = new Dimension("ratio");
|
|
427
|
+
ratio.base("whole");
|
|
428
|
+
const third = ratio.unit("third", new Rational(1, 3)); // exact, not 0.3333…
|
|
262
429
|
```
|
|
263
430
|
|
|
264
431
|
### Affine units (offset, not just scale)
|
|
265
432
|
|
|
266
433
|
```ts
|
|
434
|
+
import { Dimension, Rational } from "measurable";
|
|
435
|
+
|
|
267
436
|
const temperature = new Dimension("temperature");
|
|
268
|
-
const kelvin = temperature.base("kelvin",
|
|
437
|
+
const kelvin = temperature.base("kelvin", { symbol: "K" });
|
|
269
438
|
// value_in_base = value * scale + offset
|
|
270
|
-
const celsius = temperature.affine("celsius", { scale: 1, offset: 273.15 },
|
|
439
|
+
const celsius = temperature.affine("celsius", { scale: 1, offset: 273.15 }, {
|
|
440
|
+
symbol: "°C",
|
|
441
|
+
aliases: ["C"],
|
|
442
|
+
});
|
|
443
|
+
// Fahrenheit's 5/9 isn't a terminating decimal — give it (and the derived
|
|
444
|
+
// offset) as exact Rationals so conversions round-trip without drift.
|
|
445
|
+
const scale = new Rational(5, 9);
|
|
446
|
+
const fahrenheit = temperature.affine(
|
|
447
|
+
"fahrenheit",
|
|
448
|
+
{ scale, offset: Rational.from(273.15).minus(new Rational(32).times(scale)) },
|
|
449
|
+
{ symbol: "°F", aliases: ["F"] },
|
|
450
|
+
);
|
|
271
451
|
```
|
|
272
452
|
|
|
273
453
|
### Fully custom transforms
|
|
@@ -285,18 +465,22 @@ dim.custom("squared", {
|
|
|
285
465
|
|
|
286
466
|
### Generating SI prefixes
|
|
287
467
|
|
|
288
|
-
`definePrefixed` adds the metric prefix ladder to a reference unit and returns the
|
|
289
|
-
created units keyed by name (skipping any name that already exists).
|
|
290
|
-
`
|
|
468
|
+
`definePrefixed` adds the metric prefix ladder to a reference **unit** and returns the
|
|
469
|
+
created units keyed by name (skipping any name that already exists). It reads the
|
|
470
|
+
reference's `name`, `symbol`, and scale straight off the unit (via `scaleOf`), so each
|
|
471
|
+
generated unit gets a derived symbol (`b` → `kb`) and plural too — even when the
|
|
472
|
+
reference isn't the base unit. Pass `SI_SUBMULTIPLE_PREFIXES` to generate fractions only.
|
|
291
473
|
|
|
292
474
|
```ts
|
|
293
475
|
import { Dimension, Quantity, definePrefixed } from "measurable";
|
|
294
476
|
|
|
295
477
|
const data = new Dimension("data");
|
|
296
|
-
const bit = data.base("bit",
|
|
297
|
-
const prefixed = definePrefixed(data,
|
|
478
|
+
const bit = data.base("bit", { symbol: "b", plural: "bits" });
|
|
479
|
+
const prefixed = definePrefixed(data, bit);
|
|
298
480
|
|
|
299
|
-
new Quantity(1, prefixed.kilobit).in(bit);
|
|
481
|
+
new Quantity(1, prefixed.kilobit).in(bit); // 1000 (SI kilo = 1e3)
|
|
482
|
+
prefixed.kilobit.symbol; // "kb"
|
|
483
|
+
new Quantity(5, prefixed.kilobit).format({ unit: "symbol" }); // "5 kb"
|
|
300
484
|
```
|
|
301
485
|
|
|
302
486
|
### Tagging units into a measurement system
|
|
@@ -313,32 +497,43 @@ si.has(kilobyte); // true
|
|
|
313
497
|
### `Dimension`
|
|
314
498
|
|
|
315
499
|
- `new Dimension(name)`
|
|
316
|
-
- `.base(name,
|
|
317
|
-
- `.unit(name, scale,
|
|
318
|
-
- `.affine(name, { scale, offset },
|
|
319
|
-
- `.custom(name, { toBase, fromBase },
|
|
320
|
-
- `.convert(value, from, to)` — convert a raw number between two of its units
|
|
500
|
+
- `.base(name, def?)` — define the canonical base unit
|
|
501
|
+
- `.unit(name, scale, def?)` — linear unit (`scale` base units per unit; `number | Rational`)
|
|
502
|
+
- `.affine(name, { scale, offset }, def?)` — linear with additive offset (each `number | Rational`)
|
|
503
|
+
- `.custom(name, { toBase, fromBase }, def?)` — arbitrary inverse pair, for non-linear units
|
|
504
|
+
- `.convert(value, from, to)` — convert a raw `number` between two of its units
|
|
505
|
+
- `.convertRational(value, from, to)` → `Rational` — exact conversion between two of its units
|
|
321
506
|
- `.get(token)` — units matching a name/alias (`Unit[] | undefined`)
|
|
322
507
|
- `.has(unit)`, `.units`, `.baseUnit`
|
|
323
508
|
|
|
509
|
+
`def` is an optional `UnitDef`: `{ symbol?, plural?, aliases? }`. All three are
|
|
510
|
+
registered as parse tokens; `symbol`/`plural` are additionally stored on the `Unit`.
|
|
511
|
+
|
|
324
512
|
### `Unit`
|
|
325
513
|
|
|
326
514
|
A passive handle, normally created via a dimension's builder methods rather than
|
|
327
515
|
`new Unit` directly. Read-only properties:
|
|
328
516
|
|
|
329
517
|
- `.name` — the unit's canonical name
|
|
518
|
+
- `.symbol?` — canonical symbol (e.g. `"g"`, `"km"`), if declared
|
|
519
|
+
- `.plural?` — plural name (e.g. `"grams"`), if declared
|
|
330
520
|
- `.dimension` — the `Dimension` it belongs to
|
|
521
|
+
- `.linear` → `{ scale: Rational; offset: Rational } | undefined` — the exact transform for linear/affine units (`undefined` for `custom` ones)
|
|
331
522
|
- `.toBase(value)` → `number` — convert a value in this unit to base units
|
|
332
523
|
- `.fromBase(value)` → `number` — convert a value in base units to this unit
|
|
333
524
|
|
|
334
525
|
### `Quantity`
|
|
335
526
|
|
|
336
|
-
- `new Quantity(magnitude, unit)`
|
|
527
|
+
- `new Quantity(magnitude, unit)` — `magnitude` is a `number | Rational`; throws on a non-finite `number`
|
|
528
|
+
- `.magnitude` → `number` — getter, derived from `.rational`
|
|
529
|
+
- `.rational` → `Rational` — the exact magnitude (source of truth)
|
|
337
530
|
- `.to(target)` → `Quantity`
|
|
338
531
|
- `.in(target)` → `number`
|
|
339
|
-
- `.toString()` → `string` — e.g. `"5 kilometer"`
|
|
532
|
+
- `.toString()` → `string` — stable `"<magnitude> <name>"`, e.g. `"5 kilometer"`
|
|
533
|
+
- `.format({ unit?, locale?, numberFormat? })` → `string` — `unit`: `"auto"` (default, magnitude-aware) / `"name"` / `"plural"` / `"symbol"`; `locale` + `numberFormat` localize the magnitude via `toLocaleString`
|
|
534
|
+
- `.formatParts(options?)` → `{ magnitude, unit }` — same options as `.format`, but returns the rendered pieces separately for custom assembly (e.g. JSX)
|
|
340
535
|
- `.plus(other)` / `.minus(other)` → `Quantity` — add/subtract another quantity (aliases: `add` / `sub`)
|
|
341
|
-
- `.times(factor)` / `.dividedBy(divisor)` → `Quantity` — scale by a number (aliases: `mul` / `div`)
|
|
536
|
+
- `.times(factor)` / `.dividedBy(divisor)` → `Quantity` — scale by a `number | Rational` (aliases: `mul` / `div`)
|
|
342
537
|
- `.ratioTo(other)` → `number` — dimensionless ratio (how many of `other` fit in this)
|
|
343
538
|
- `.negate()` / `.abs()` → `Quantity`
|
|
344
539
|
- `.clamp(lower, upper)` → `Quantity` — bound to a range, in this unit
|
|
@@ -351,6 +546,23 @@ A passive handle, normally created via a dimension's builder methods rather than
|
|
|
351
546
|
- `Quantity.min(...quantities)` / `Quantity.max(...quantities)` / `Quantity.sum(...quantities)` → `Quantity`
|
|
352
547
|
- `Quantity.parse(input, dimension, { prefer? })` → `Quantity`
|
|
353
548
|
|
|
549
|
+
### `Rational`
|
|
550
|
+
|
|
551
|
+
An exact rational number (`n / d`), stored as `bigint`s in lowest terms with a
|
|
552
|
+
positive denominator. Immutable; every operation returns a new `Rational`. Used
|
|
553
|
+
internally for lossless conversions and arithmetic, but you can construct one to
|
|
554
|
+
pass anywhere a magnitude or scale is accepted.
|
|
555
|
+
|
|
556
|
+
- `new Rational(numerator, denominator?)` — from integers (`bigint | number`; denominator defaults to `1`). Throws on a non-integer `number` or a zero denominator.
|
|
557
|
+
- `Rational.from(value)` — coerce a `number | Rational` (a `number` is read as its exact terminating decimal, e.g. `0.0254` → `254/10000`)
|
|
558
|
+
- `.n` / `.d` → `bigint` — numerator and denominator
|
|
559
|
+
- `.plus(other)` / `.minus(other)` / `.times(other)` / `.dividedBy(other)` → `Rational` (aliases: `add` / `sub` / `mul` / `div`)
|
|
560
|
+
- `.negate()` / `.abs()` → `Rational`
|
|
561
|
+
- `.equals(other)` → `boolean` (alias: `eq`)
|
|
562
|
+
- `.compare(other)` → `-1 | 0 | 1`
|
|
563
|
+
- `.sign()` → `-1 | 0 | 1`
|
|
564
|
+
- `.toNumber()` → `number` — collapse to the nearest `number`
|
|
565
|
+
|
|
354
566
|
### `MeasurementSystem`
|
|
355
567
|
|
|
356
568
|
- `new MeasurementSystem(name)`
|
|
@@ -364,6 +576,12 @@ A passive handle, normally created via a dimension's builder methods rather than
|
|
|
364
576
|
- `UnknownUnitError` — a parsed token matches no unit
|
|
365
577
|
- `AmbiguousUnitError` — a parsed token matches several units and no `prefer` was given
|
|
366
578
|
|
|
579
|
+
## Changelog
|
|
580
|
+
|
|
581
|
+
See [CHANGELOG.md](https://github.com/mhuggins/measurable/blob/main/CHANGELOG.md)
|
|
582
|
+
for release notes. Note that v2.0.0 is a breaking release — see its entry for the
|
|
583
|
+
migration details.
|
|
584
|
+
|
|
367
585
|
## License
|
|
368
586
|
|
|
369
587
|
ISC
|
package/dist/dimensions/angle.js
CHANGED
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.microradian = exports.milliradian = exports.metricAngle = exports.turn = exports.gradian = exports.degree = exports.radian = exports.angle = void 0;
|
|
4
4
|
const Dimension_1 = require("../lib/Dimension");
|
|
5
|
-
const
|
|
5
|
+
const definePrefixed_1 = require("../utils/definePrefixed");
|
|
6
6
|
/** Plane angle. Base unit: radian. */
|
|
7
7
|
exports.angle = new Dimension_1.Dimension("angle");
|
|
8
|
-
exports.radian = exports.angle.base("radian",
|
|
9
|
-
exports.degree = exports.angle.unit("degree", Math.PI / 180,
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
exports.radian = exports.angle.base("radian", { symbol: "rad", plural: "radians" });
|
|
9
|
+
exports.degree = exports.angle.unit("degree", Math.PI / 180, {
|
|
10
|
+
symbol: "°",
|
|
11
|
+
plural: "degrees",
|
|
12
|
+
aliases: ["deg"],
|
|
13
|
+
});
|
|
14
|
+
exports.gradian = exports.angle.unit("gradian", Math.PI / 200, { symbol: "grad", plural: "gradians" });
|
|
15
|
+
exports.turn = exports.angle.unit("turn", 2 * Math.PI, {
|
|
16
|
+
plural: "turns",
|
|
17
|
+
aliases: ["revolution", "revolutions"],
|
|
18
|
+
});
|
|
12
19
|
/** SI-submultiple radians (milliradian, microradian, …); larger angles use degree/turn. */
|
|
13
|
-
exports.metricAngle = (0,
|
|
20
|
+
exports.metricAngle = (0, definePrefixed_1.definePrefixed)(exports.angle, exports.radian, definePrefixed_1.SI_SUBMULTIPLE_PREFIXES);
|
|
14
21
|
exports.milliradian = exports.metricAngle.milliradian, exports.microradian = exports.metricAngle.microradian;
|