@corva/convert-units 3.1.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.
Files changed (54) hide show
  1. package/definitions/acousticSlowness.json +34 -0
  2. package/definitions/angle.json +106 -0
  3. package/definitions/anglePerLength.json +52 -0
  4. package/definitions/angularVelocity.json +87 -0
  5. package/definitions/area.json +106 -0
  6. package/definitions/concentration.json +34 -0
  7. package/definitions/current.json +52 -0
  8. package/definitions/density.json +160 -0
  9. package/definitions/digital.json +106 -0
  10. package/definitions/each.json +20 -0
  11. package/definitions/energy.json +61 -0
  12. package/definitions/force.json +106 -0
  13. package/definitions/gammaRadiation.json +34 -0
  14. package/definitions/gasConcentration.json +124 -0
  15. package/definitions/gasFlowRate.json +34 -0
  16. package/definitions/gasVolume.json +250 -0
  17. package/definitions/gravity.json +43 -0
  18. package/definitions/gravityRMS.json +34 -0
  19. package/definitions/inversePressure.json +61 -0
  20. package/definitions/length.json +97 -0
  21. package/definitions/lengthPerAngle.json +43 -0
  22. package/definitions/mass.json +115 -0
  23. package/definitions/massFlowRate.json +205 -0
  24. package/definitions/mpl.json +43 -0
  25. package/definitions/partsPer.json +47 -0
  26. package/definitions/permiability.json +34 -0
  27. package/definitions/porosity.json +43 -0
  28. package/definitions/power.json +43 -0
  29. package/definitions/pressure.json +142 -0
  30. package/definitions/pressureGradient.json +43 -0
  31. package/definitions/proportion.json +52 -0
  32. package/definitions/resistivity.json +34 -0
  33. package/definitions/revolutionPerVolume.json +34 -0
  34. package/definitions/speed.json +97 -0
  35. package/definitions/spontaneousPotential.json +34 -0
  36. package/definitions/strokesRate.json +70 -0
  37. package/definitions/surveyLength.json +43 -0
  38. package/definitions/temperature.json +44 -0
  39. package/definitions/time.json +100 -0
  40. package/definitions/torque.json +61 -0
  41. package/definitions/unitBucketMapping.json +404 -0
  42. package/definitions/unitless.json +34 -0
  43. package/definitions/viscosity.json +28 -0
  44. package/definitions/voltage.json +70 -0
  45. package/definitions/volume.json +241 -0
  46. package/definitions/volumeConcentration.json +34 -0
  47. package/definitions/volumeFlowRate.json +385 -0
  48. package/dist/index.cjs +223 -0
  49. package/dist/index.cjs.map +1 -0
  50. package/dist/index.d.cts +58 -0
  51. package/dist/index.d.ts +58 -0
  52. package/dist/index.js +172 -0
  53. package/dist/index.js.map +1 -0
  54. package/package.json +42 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ bucketMapping: () => bucketMapping,
34
+ convert: () => convert,
35
+ default: () => convert,
36
+ describe: () => describe,
37
+ getMeasures: () => getMeasures,
38
+ getUnit: () => getUnit,
39
+ getUnitForPair: () => getUnitForPair,
40
+ getUnitKeyByAlias: () => getUnitKeyByAlias,
41
+ listUnits: () => listUnits,
42
+ listUnitsWithAliases: () => listUnitsWithAliases,
43
+ possibilities: () => possibilities,
44
+ toBest: () => toBest
45
+ });
46
+ module.exports = __toCommonJS(index_exports);
47
+
48
+ // node_modules/tsup/assets/cjs_shims.js
49
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
50
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
51
+
52
+ // src/loader.ts
53
+ var import_node_fs = __toESM(require("fs"), 1);
54
+ var import_node_path = __toESM(require("path"), 1);
55
+ var import_node_url = require("url");
56
+ var UNIT_BUCKET_MAPPING_FILE = "unitBucketMapping.json";
57
+ var DEFS_DIR = import_node_path.default.resolve(import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl)), "..", "definitions");
58
+ var loadDefinitions = () => {
59
+ const result = {};
60
+ const files = import_node_fs.default.readdirSync(DEFS_DIR).filter((f) => f.endsWith(".json") && f !== UNIT_BUCKET_MAPPING_FILE);
61
+ for (const file of files) {
62
+ const name = import_node_path.default.basename(file, ".json");
63
+ const raw = JSON.parse(import_node_fs.default.readFileSync(import_node_path.default.join(DEFS_DIR, file), "utf-8"));
64
+ if (raw._anchors) {
65
+ for (const key of Object.keys(raw._anchors)) {
66
+ const anchor = raw._anchors[key];
67
+ if (typeof anchor.transform === "string") {
68
+ anchor.transform = new Function("val", `return ${anchor.transform}`);
69
+ }
70
+ }
71
+ }
72
+ result[name] = raw;
73
+ }
74
+ if (result.density) result.formationDensity = result.density;
75
+ const DEPRIORITIZED = [
76
+ "density",
77
+ "formationDensity",
78
+ "concentration",
79
+ "gasConcentration",
80
+ "force",
81
+ "gravity",
82
+ "gasVolume",
83
+ "spontaneousPotential"
84
+ ];
85
+ const deprioritized = {};
86
+ for (const key of DEPRIORITIZED) {
87
+ if (result[key]) {
88
+ deprioritized[key] = result[key];
89
+ delete result[key];
90
+ }
91
+ }
92
+ return { ...result, ...deprioritized };
93
+ };
94
+ var measures = loadDefinitions();
95
+ var bucketMapping = JSON.parse(
96
+ import_node_fs.default.readFileSync(import_node_path.default.join(DEFS_DIR, UNIT_BUCKET_MAPPING_FILE), "utf-8")
97
+ );
98
+
99
+ // src/errors.ts
100
+ var throwUnsupportedUnitError = (what, validUnits) => {
101
+ throw new Error(`Unsupported unit ${what}, use one of: ${validUnits.join(", ")}`);
102
+ };
103
+ var throwUnsupportedCompatibilityError = (abbr, measure) => {
104
+ throw new Error(`Unsupported compatibility for unit ${abbr} and measure ${measure}`);
105
+ };
106
+ var throwIncompatibleMeasuresError = (destMeasure, originMeasure) => {
107
+ throw new Error(`Cannot convert incompatible measures of ${destMeasure} and ${originMeasure}`);
108
+ };
109
+
110
+ // src/core.ts
111
+ var unitIndex = /* @__PURE__ */ new Map();
112
+ var measureIndex = /* @__PURE__ */ new Map();
113
+ var aliasMap = /* @__PURE__ */ new Map();
114
+ var _buildIndexes = () => {
115
+ const all = [];
116
+ for (const [measure, systems] of Object.entries(measures)) {
117
+ for (const [system, units] of Object.entries(systems)) {
118
+ if (system === "_anchors") continue;
119
+ for (const [abbr, unit] of Object.entries(units)) {
120
+ const entry = { abbr, unit, system, measure };
121
+ all.push(entry);
122
+ if (!unitIndex.has(abbr)) unitIndex.set(abbr, entry);
123
+ if (!measureIndex.has(measure)) measureIndex.set(measure, []);
124
+ measureIndex.get(measure).push(entry);
125
+ aliasMap.set(abbr, abbr);
126
+ for (const alias of unit.aliases ?? []) aliasMap.set(alias, abbr);
127
+ }
128
+ }
129
+ }
130
+ return all;
131
+ };
132
+ var allUnits = _buildIndexes();
133
+ var getUnit = (abbr, measure) => {
134
+ if (measure) {
135
+ const entry = measureIndex.get(measure)?.find((e) => e.abbr === abbr || e.unit.aliases?.includes(abbr));
136
+ if (!entry) throwUnsupportedCompatibilityError(abbr, measure);
137
+ return entry;
138
+ }
139
+ const canonical = aliasMap.get(abbr);
140
+ return canonical !== void 0 ? unitIndex.get(canonical) : void 0;
141
+ };
142
+ var getUnitForPair = (abbrOne, abbrTwo) => {
143
+ const one = unitIndex.get(abbrOne);
144
+ const two = unitIndex.get(abbrTwo);
145
+ return one && two && one.measure === two.measure ? [one, two] : null;
146
+ };
147
+ var toPlainUnit = ({ abbr, measure, system, unit }) => ({
148
+ abbr,
149
+ measure,
150
+ system,
151
+ singular: unit.name.singular,
152
+ plural: unit.name.plural,
153
+ display: unit.name.display
154
+ });
155
+ var _toPlainUnitWithAlias = (entry) => ({
156
+ ...toPlainUnit(entry),
157
+ aliases: entry.unit.aliases
158
+ });
159
+ var listUnits = (measure, withAliases = false) => {
160
+ const decorator = withAliases ? _toPlainUnitWithAlias : toPlainUnit;
161
+ const entries = measure ? measureIndex.get(measure) ?? [] : allUnits;
162
+ return entries.map(decorator);
163
+ };
164
+ var getPossibilities = (measure, origin) => {
165
+ const m = measure ?? origin?.measure;
166
+ if (!m) return [...unitIndex.keys()];
167
+ return (measureIndex.get(m) ?? []).map((e) => e.abbr);
168
+ };
169
+ var convert = (value, from, to, measure) => {
170
+ const origin = getUnit(from, measure) ?? throwUnsupportedUnitError(from, getPossibilities());
171
+ const dest = getUnit(to, measure) ?? throwUnsupportedUnitError(to, getPossibilities());
172
+ if (origin.abbr === dest.abbr) return value;
173
+ let src = origin;
174
+ let tgt = dest;
175
+ if (dest.measure !== origin.measure) {
176
+ if (measure) throwIncompatibleMeasuresError(dest.measure, origin.measure);
177
+ [tgt, src] = getUnitForPair(dest.abbr, origin.abbr) ?? throwIncompatibleMeasuresError(dest.measure, origin.measure);
178
+ }
179
+ let result = value * src.unit.to_anchor;
180
+ if (src.unit.anchor_shift) result -= src.unit.anchor_shift;
181
+ if (src.system !== tgt.system) {
182
+ const anchor = measures[src.measure]._anchors[src.system];
183
+ result = typeof anchor.transform === "function" ? anchor.transform(result) : result * anchor.ratio;
184
+ }
185
+ if (tgt.unit.anchor_shift) result += tgt.unit.anchor_shift;
186
+ return result / tgt.unit.to_anchor;
187
+ };
188
+ var toBest = (value, from, measure, exclude = []) => {
189
+ const origin = getUnit(from, measure);
190
+ if (!origin) return void 0;
191
+ let best;
192
+ for (const abbr of getPossibilities(origin.measure)) {
193
+ if (exclude.includes(abbr)) continue;
194
+ const entry = measureIndex.get(origin.measure)?.find((e) => e.abbr === abbr);
195
+ if (!entry || entry.system !== origin.system) continue;
196
+ const result = convert(value, from, abbr, origin.measure);
197
+ const { singular, plural, display } = toPlainUnit(entry);
198
+ if (!best || result >= 1 && result < best.val) {
199
+ best = { val: result, unit: abbr, singular, plural, display };
200
+ }
201
+ }
202
+ return best;
203
+ };
204
+ var getMeasures = () => Object.keys(measures);
205
+ var describe = (abbr) => toPlainUnit(getUnit(abbr) ?? throwUnsupportedUnitError(abbr, getPossibilities()));
206
+ var listUnitsWithAliases = (measure) => listUnits(measure, true);
207
+ var possibilities = (measure) => getPossibilities(measure);
208
+ var getUnitKeyByAlias = (alias) => aliasMap.get(alias);
209
+ // Annotate the CommonJS export names for ESM import in node:
210
+ 0 && (module.exports = {
211
+ bucketMapping,
212
+ convert,
213
+ describe,
214
+ getMeasures,
215
+ getUnit,
216
+ getUnitForPair,
217
+ getUnitKeyByAlias,
218
+ listUnits,
219
+ listUnitsWithAliases,
220
+ possibilities,
221
+ toBest
222
+ });
223
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/loader.ts","../src/errors.ts","../src/core.ts"],"sourcesContent":["export type {\n UnitDefinition,\n MeasureDefinition,\n SystemAnchor,\n ResolvedUnit,\n ConversionResult,\n PlainUnit,\n BucketMapping,\n UnitNames,\n} from './types';\n\nexport {\n convert,\n getMeasures,\n describe,\n getUnit,\n getUnitForPair,\n listUnits,\n listUnitsWithAliases,\n possibilities,\n toBest,\n bucketMapping,\n getUnitKeyByAlias,\n} from './core';\n\nexport { convert as default } from './core';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { MeasureDefinition, BucketMapping } from './types';\n\nconst UNIT_BUCKET_MAPPING_FILE = 'unitBucketMapping.json';\nconst DEFS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'definitions');\n\nconst loadDefinitions = (): Record<string, MeasureDefinition> => {\n const result: Record<string, MeasureDefinition> = {};\n const files = fs.readdirSync(DEFS_DIR).filter((f) => f.endsWith('.json') && f !== UNIT_BUCKET_MAPPING_FILE);\n\n for (const file of files) {\n const name = path.basename(file, '.json');\n const raw = JSON.parse(fs.readFileSync(path.join(DEFS_DIR, file), 'utf-8'));\n\n if (raw._anchors) {\n for (const key of Object.keys(raw._anchors)) {\n const anchor = raw._anchors[key];\n if (typeof anchor.transform === 'string') {\n anchor.transform = new Function('val', `return ${anchor.transform}`) as (val: number) => number;\n }\n }\n }\n\n result[name] = raw;\n }\n\n if (result.density) result.formationDensity = result.density;\n\n // Restore the same lookup priority as the original library.\n //\n // Measures listed here are moved to the END of the insertion order so that\n // \"first occurrence wins\" in buildIndexes() resolves shared unit keys correctly:\n //\n // density / formationDensity — share kPa/m and psi/ft with pressureGradient;\n // pressureGradient anchors must win\n // concentration — shares ppm with partsPer; partsPer must win\n // gasConcentration — shares ppm with partsPer; partsPer must win\n // force / gravity — share g with mass; mass (gram) must win\n // gasVolume — shares gal/bbl/m3 with volume; liquid anchors must win\n // spontaneousPotential — shares mV with voltage; voltage must win\n const DEPRIORITIZED = [\n 'density',\n 'formationDensity',\n 'concentration',\n 'gasConcentration',\n 'force',\n 'gravity',\n 'gasVolume',\n 'spontaneousPotential',\n ];\n const deprioritized: Record<string, MeasureDefinition> = {};\n for (const key of DEPRIORITIZED) {\n if (result[key]) {\n deprioritized[key] = result[key];\n delete result[key];\n }\n }\n return { ...result, ...deprioritized };\n};\n\nexport const measures: Record<string, MeasureDefinition> = loadDefinitions();\n\nexport const bucketMapping: BucketMapping = JSON.parse(\n fs.readFileSync(path.join(DEFS_DIR, UNIT_BUCKET_MAPPING_FILE), 'utf-8'),\n);\n","export const throwUnsupportedUnitError = (what: string, validUnits: string[]): never => {\n throw new Error(`Unsupported unit ${what}, use one of: ${validUnits.join(', ')}`);\n};\n\nexport const throwUnsupportedCompatibilityError = (abbr: string, measure: string): never => {\n throw new Error(`Unsupported compatibility for unit ${abbr} and measure ${measure}`);\n};\n\nexport const throwIncompatibleMeasuresError = (destMeasure: string, originMeasure: string): never => {\n throw new Error(`Cannot convert incompatible measures of ${destMeasure} and ${originMeasure}`);\n};\n","import { measures, bucketMapping } from './loader';\nimport {\n throwUnsupportedCompatibilityError,\n throwUnsupportedUnitError,\n throwIncompatibleMeasuresError,\n} from './errors';\nimport type { UnitDefinition, ResolvedUnit, PlainUnit, ConversionResult } from './types';\n\nconst unitIndex = new Map<string, ResolvedUnit>();\nconst measureIndex = new Map<string, ResolvedUnit[]>();\nconst aliasMap = new Map<string, string>();\n\nconst _buildIndexes = (): ResolvedUnit[] => {\n const all: ResolvedUnit[] = [];\n\n for (const [measure, systems] of Object.entries(measures)) {\n for (const [system, units] of Object.entries(systems)) {\n if (system === '_anchors') continue;\n for (const [abbr, unit] of Object.entries(units as Record<string, UnitDefinition>)) {\n const entry: ResolvedUnit = { abbr, unit, system, measure };\n all.push(entry);\n\n // First occurrence wins (preserves density over formationDensity for global lookups).\n if (!unitIndex.has(abbr)) unitIndex.set(abbr, entry);\n\n if (!measureIndex.has(measure)) measureIndex.set(measure, []);\n measureIndex.get(measure)!.push(entry);\n\n aliasMap.set(abbr, abbr);\n for (const alias of unit.aliases ?? []) aliasMap.set(alias, abbr);\n }\n }\n }\n\n return all;\n};\n\nconst allUnits = _buildIndexes();\n\n// Lookup helpers\nconst getUnit = (abbr: string, measure?: string): ResolvedUnit | undefined => {\n if (measure) {\n const entry = measureIndex.get(measure)?.find((e) => e.abbr === abbr || e.unit.aliases?.includes(abbr));\n if (!entry) throwUnsupportedCompatibilityError(abbr, measure);\n return entry;\n }\n const canonical = aliasMap.get(abbr);\n return canonical !== undefined ? unitIndex.get(canonical) : undefined;\n};\n\nconst getUnitForPair = (abbrOne: string, abbrTwo: string): [ResolvedUnit, ResolvedUnit] | null => {\n const one = unitIndex.get(abbrOne);\n const two = unitIndex.get(abbrTwo);\n return one && two && one.measure === two.measure ? [one, two] : null;\n};\n\nconst toPlainUnit = ({ abbr, measure, system, unit }: ResolvedUnit): PlainUnit => ({\n abbr,\n measure,\n system,\n singular: unit.name.singular,\n plural: unit.name.plural,\n display: unit.name.display,\n});\n\nconst _toPlainUnitWithAlias = (entry: ResolvedUnit): PlainUnit => ({\n ...toPlainUnit(entry),\n aliases: entry.unit.aliases,\n});\n\nconst listUnits = (measure?: string, withAliases = false): PlainUnit[] => {\n const decorator = withAliases ? _toPlainUnitWithAlias : toPlainUnit;\n const entries = measure ? (measureIndex.get(measure) ?? []) : allUnits;\n return entries.map(decorator);\n};\n\nconst getPossibilities = (measure?: string, origin?: ResolvedUnit): string[] => {\n const m = measure ?? origin?.measure;\n if (!m) return [...unitIndex.keys()];\n return (measureIndex.get(m) ?? []).map((e) => e.abbr);\n};\n\nconst convert = (value: number, from: string, to: string, measure?: string): number => {\n const origin = getUnit(from, measure) ?? throwUnsupportedUnitError(from, getPossibilities());\n const dest = getUnit(to, measure) ?? throwUnsupportedUnitError(to, getPossibilities());\n\n if (origin.abbr === dest.abbr) return value;\n\n let src = origin;\n let tgt = dest;\n\n if (dest.measure !== origin.measure) {\n if (measure) throwIncompatibleMeasuresError(dest.measure, origin.measure);\n [tgt, src] =\n getUnitForPair(dest.abbr, origin.abbr) ?? throwIncompatibleMeasuresError(dest.measure, origin.measure);\n }\n\n let result = value * src.unit.to_anchor;\n if (src.unit.anchor_shift) result -= src.unit.anchor_shift;\n\n if (src.system !== tgt.system) {\n const anchor = measures[src.measure]._anchors[src.system];\n result = typeof anchor.transform === 'function' ? anchor.transform(result) : result * anchor.ratio!;\n }\n\n if (tgt.unit.anchor_shift) result += tgt.unit.anchor_shift;\n return result / tgt.unit.to_anchor;\n};\n\nconst toBest = (\n value: number,\n from: string,\n measure?: string,\n exclude: string[] = [],\n): ConversionResult | undefined => {\n const origin = getUnit(from, measure);\n if (!origin) return undefined;\n\n let best: ConversionResult | undefined;\n\n for (const abbr of getPossibilities(origin.measure)) {\n if (exclude.includes(abbr)) continue;\n const entry = measureIndex.get(origin.measure)?.find((e) => e.abbr === abbr);\n if (!entry || entry.system !== origin.system) continue;\n\n const result = convert(value, from, abbr, origin.measure);\n const { singular, plural, display } = toPlainUnit(entry);\n if (!best || (result >= 1 && result < best.val)) {\n best = { val: result, unit: abbr, singular, plural, display };\n }\n }\n\n return best;\n};\n\nconst getMeasures = (): string[] => Object.keys(measures);\n\nconst describe = (abbr: string): PlainUnit =>\n toPlainUnit(getUnit(abbr) ?? throwUnsupportedUnitError(abbr, getPossibilities()));\n\nconst listUnitsWithAliases = (measure?: string): PlainUnit[] => listUnits(measure, true);\n\nconst possibilities = (measure?: string): string[] => getPossibilities(measure);\n\nconst getUnitKeyByAlias = (alias: string): string | undefined => aliasMap.get(alias);\n\nexport {\n measures,\n bucketMapping,\n aliasMap,\n getUnit,\n getUnitForPair,\n toPlainUnit,\n listUnits,\n listUnitsWithAliases,\n getMeasures,\n describe,\n possibilities,\n getUnitKeyByAlias,\n getPossibilities,\n convert,\n toBest,\n};\n"],"mappings":"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","names":["path","fs"]}
@@ -0,0 +1,58 @@
1
+ type UnitNames = {
2
+ singular: string;
3
+ plural: string;
4
+ display: string;
5
+ };
6
+ type UnitDefinition = {
7
+ name: UnitNames;
8
+ to_anchor: number;
9
+ anchor_shift?: number;
10
+ aliases?: string[];
11
+ };
12
+ type SystemAnchor = {
13
+ unit: string;
14
+ ratio?: number;
15
+ transform?: (val: number) => number;
16
+ };
17
+ type MeasureDefinition = {
18
+ _anchors: Record<string, SystemAnchor>;
19
+ [system: string]: Record<string, UnitDefinition> | Record<string, SystemAnchor>;
20
+ };
21
+ type ResolvedUnit = {
22
+ abbr: string;
23
+ measure: string;
24
+ system: string;
25
+ unit: UnitDefinition;
26
+ };
27
+ type ConversionResult = {
28
+ val: number;
29
+ unit: string;
30
+ singular: string;
31
+ plural: string;
32
+ display: string;
33
+ };
34
+ type PlainUnit = {
35
+ abbr: string;
36
+ measure: string;
37
+ system: string;
38
+ singular: string;
39
+ plural: string;
40
+ display: string;
41
+ aliases?: string[];
42
+ };
43
+ type BucketMapping = Record<string, string[]>;
44
+
45
+ declare const bucketMapping: BucketMapping;
46
+
47
+ declare const getUnit: (abbr: string, measure?: string) => ResolvedUnit | undefined;
48
+ declare const getUnitForPair: (abbrOne: string, abbrTwo: string) => [ResolvedUnit, ResolvedUnit] | null;
49
+ declare const listUnits: (measure?: string, withAliases?: boolean) => PlainUnit[];
50
+ declare const convert: (value: number, from: string, to: string, measure?: string) => number;
51
+ declare const toBest: (value: number, from: string, measure?: string, exclude?: string[]) => ConversionResult | undefined;
52
+ declare const getMeasures: () => string[];
53
+ declare const describe: (abbr: string) => PlainUnit;
54
+ declare const listUnitsWithAliases: (measure?: string) => PlainUnit[];
55
+ declare const possibilities: (measure?: string) => string[];
56
+ declare const getUnitKeyByAlias: (alias: string) => string | undefined;
57
+
58
+ export { type BucketMapping, type ConversionResult, type MeasureDefinition, type PlainUnit, type ResolvedUnit, type SystemAnchor, type UnitDefinition, type UnitNames, bucketMapping, convert, convert as default, describe, getMeasures, getUnit, getUnitForPair, getUnitKeyByAlias, listUnits, listUnitsWithAliases, possibilities, toBest };
@@ -0,0 +1,58 @@
1
+ type UnitNames = {
2
+ singular: string;
3
+ plural: string;
4
+ display: string;
5
+ };
6
+ type UnitDefinition = {
7
+ name: UnitNames;
8
+ to_anchor: number;
9
+ anchor_shift?: number;
10
+ aliases?: string[];
11
+ };
12
+ type SystemAnchor = {
13
+ unit: string;
14
+ ratio?: number;
15
+ transform?: (val: number) => number;
16
+ };
17
+ type MeasureDefinition = {
18
+ _anchors: Record<string, SystemAnchor>;
19
+ [system: string]: Record<string, UnitDefinition> | Record<string, SystemAnchor>;
20
+ };
21
+ type ResolvedUnit = {
22
+ abbr: string;
23
+ measure: string;
24
+ system: string;
25
+ unit: UnitDefinition;
26
+ };
27
+ type ConversionResult = {
28
+ val: number;
29
+ unit: string;
30
+ singular: string;
31
+ plural: string;
32
+ display: string;
33
+ };
34
+ type PlainUnit = {
35
+ abbr: string;
36
+ measure: string;
37
+ system: string;
38
+ singular: string;
39
+ plural: string;
40
+ display: string;
41
+ aliases?: string[];
42
+ };
43
+ type BucketMapping = Record<string, string[]>;
44
+
45
+ declare const bucketMapping: BucketMapping;
46
+
47
+ declare const getUnit: (abbr: string, measure?: string) => ResolvedUnit | undefined;
48
+ declare const getUnitForPair: (abbrOne: string, abbrTwo: string) => [ResolvedUnit, ResolvedUnit] | null;
49
+ declare const listUnits: (measure?: string, withAliases?: boolean) => PlainUnit[];
50
+ declare const convert: (value: number, from: string, to: string, measure?: string) => number;
51
+ declare const toBest: (value: number, from: string, measure?: string, exclude?: string[]) => ConversionResult | undefined;
52
+ declare const getMeasures: () => string[];
53
+ declare const describe: (abbr: string) => PlainUnit;
54
+ declare const listUnitsWithAliases: (measure?: string) => PlainUnit[];
55
+ declare const possibilities: (measure?: string) => string[];
56
+ declare const getUnitKeyByAlias: (alias: string) => string | undefined;
57
+
58
+ export { type BucketMapping, type ConversionResult, type MeasureDefinition, type PlainUnit, type ResolvedUnit, type SystemAnchor, type UnitDefinition, type UnitNames, bucketMapping, convert, convert as default, describe, getMeasures, getUnit, getUnitForPair, getUnitKeyByAlias, listUnits, listUnitsWithAliases, possibilities, toBest };
package/dist/index.js ADDED
@@ -0,0 +1,172 @@
1
+ // src/loader.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ var UNIT_BUCKET_MAPPING_FILE = "unitBucketMapping.json";
6
+ var DEFS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "definitions");
7
+ var loadDefinitions = () => {
8
+ const result = {};
9
+ const files = fs.readdirSync(DEFS_DIR).filter((f) => f.endsWith(".json") && f !== UNIT_BUCKET_MAPPING_FILE);
10
+ for (const file of files) {
11
+ const name = path.basename(file, ".json");
12
+ const raw = JSON.parse(fs.readFileSync(path.join(DEFS_DIR, file), "utf-8"));
13
+ if (raw._anchors) {
14
+ for (const key of Object.keys(raw._anchors)) {
15
+ const anchor = raw._anchors[key];
16
+ if (typeof anchor.transform === "string") {
17
+ anchor.transform = new Function("val", `return ${anchor.transform}`);
18
+ }
19
+ }
20
+ }
21
+ result[name] = raw;
22
+ }
23
+ if (result.density) result.formationDensity = result.density;
24
+ const DEPRIORITIZED = [
25
+ "density",
26
+ "formationDensity",
27
+ "concentration",
28
+ "gasConcentration",
29
+ "force",
30
+ "gravity",
31
+ "gasVolume",
32
+ "spontaneousPotential"
33
+ ];
34
+ const deprioritized = {};
35
+ for (const key of DEPRIORITIZED) {
36
+ if (result[key]) {
37
+ deprioritized[key] = result[key];
38
+ delete result[key];
39
+ }
40
+ }
41
+ return { ...result, ...deprioritized };
42
+ };
43
+ var measures = loadDefinitions();
44
+ var bucketMapping = JSON.parse(
45
+ fs.readFileSync(path.join(DEFS_DIR, UNIT_BUCKET_MAPPING_FILE), "utf-8")
46
+ );
47
+
48
+ // src/errors.ts
49
+ var throwUnsupportedUnitError = (what, validUnits) => {
50
+ throw new Error(`Unsupported unit ${what}, use one of: ${validUnits.join(", ")}`);
51
+ };
52
+ var throwUnsupportedCompatibilityError = (abbr, measure) => {
53
+ throw new Error(`Unsupported compatibility for unit ${abbr} and measure ${measure}`);
54
+ };
55
+ var throwIncompatibleMeasuresError = (destMeasure, originMeasure) => {
56
+ throw new Error(`Cannot convert incompatible measures of ${destMeasure} and ${originMeasure}`);
57
+ };
58
+
59
+ // src/core.ts
60
+ var unitIndex = /* @__PURE__ */ new Map();
61
+ var measureIndex = /* @__PURE__ */ new Map();
62
+ var aliasMap = /* @__PURE__ */ new Map();
63
+ var _buildIndexes = () => {
64
+ const all = [];
65
+ for (const [measure, systems] of Object.entries(measures)) {
66
+ for (const [system, units] of Object.entries(systems)) {
67
+ if (system === "_anchors") continue;
68
+ for (const [abbr, unit] of Object.entries(units)) {
69
+ const entry = { abbr, unit, system, measure };
70
+ all.push(entry);
71
+ if (!unitIndex.has(abbr)) unitIndex.set(abbr, entry);
72
+ if (!measureIndex.has(measure)) measureIndex.set(measure, []);
73
+ measureIndex.get(measure).push(entry);
74
+ aliasMap.set(abbr, abbr);
75
+ for (const alias of unit.aliases ?? []) aliasMap.set(alias, abbr);
76
+ }
77
+ }
78
+ }
79
+ return all;
80
+ };
81
+ var allUnits = _buildIndexes();
82
+ var getUnit = (abbr, measure) => {
83
+ if (measure) {
84
+ const entry = measureIndex.get(measure)?.find((e) => e.abbr === abbr || e.unit.aliases?.includes(abbr));
85
+ if (!entry) throwUnsupportedCompatibilityError(abbr, measure);
86
+ return entry;
87
+ }
88
+ const canonical = aliasMap.get(abbr);
89
+ return canonical !== void 0 ? unitIndex.get(canonical) : void 0;
90
+ };
91
+ var getUnitForPair = (abbrOne, abbrTwo) => {
92
+ const one = unitIndex.get(abbrOne);
93
+ const two = unitIndex.get(abbrTwo);
94
+ return one && two && one.measure === two.measure ? [one, two] : null;
95
+ };
96
+ var toPlainUnit = ({ abbr, measure, system, unit }) => ({
97
+ abbr,
98
+ measure,
99
+ system,
100
+ singular: unit.name.singular,
101
+ plural: unit.name.plural,
102
+ display: unit.name.display
103
+ });
104
+ var _toPlainUnitWithAlias = (entry) => ({
105
+ ...toPlainUnit(entry),
106
+ aliases: entry.unit.aliases
107
+ });
108
+ var listUnits = (measure, withAliases = false) => {
109
+ const decorator = withAliases ? _toPlainUnitWithAlias : toPlainUnit;
110
+ const entries = measure ? measureIndex.get(measure) ?? [] : allUnits;
111
+ return entries.map(decorator);
112
+ };
113
+ var getPossibilities = (measure, origin) => {
114
+ const m = measure ?? origin?.measure;
115
+ if (!m) return [...unitIndex.keys()];
116
+ return (measureIndex.get(m) ?? []).map((e) => e.abbr);
117
+ };
118
+ var convert = (value, from, to, measure) => {
119
+ const origin = getUnit(from, measure) ?? throwUnsupportedUnitError(from, getPossibilities());
120
+ const dest = getUnit(to, measure) ?? throwUnsupportedUnitError(to, getPossibilities());
121
+ if (origin.abbr === dest.abbr) return value;
122
+ let src = origin;
123
+ let tgt = dest;
124
+ if (dest.measure !== origin.measure) {
125
+ if (measure) throwIncompatibleMeasuresError(dest.measure, origin.measure);
126
+ [tgt, src] = getUnitForPair(dest.abbr, origin.abbr) ?? throwIncompatibleMeasuresError(dest.measure, origin.measure);
127
+ }
128
+ let result = value * src.unit.to_anchor;
129
+ if (src.unit.anchor_shift) result -= src.unit.anchor_shift;
130
+ if (src.system !== tgt.system) {
131
+ const anchor = measures[src.measure]._anchors[src.system];
132
+ result = typeof anchor.transform === "function" ? anchor.transform(result) : result * anchor.ratio;
133
+ }
134
+ if (tgt.unit.anchor_shift) result += tgt.unit.anchor_shift;
135
+ return result / tgt.unit.to_anchor;
136
+ };
137
+ var toBest = (value, from, measure, exclude = []) => {
138
+ const origin = getUnit(from, measure);
139
+ if (!origin) return void 0;
140
+ let best;
141
+ for (const abbr of getPossibilities(origin.measure)) {
142
+ if (exclude.includes(abbr)) continue;
143
+ const entry = measureIndex.get(origin.measure)?.find((e) => e.abbr === abbr);
144
+ if (!entry || entry.system !== origin.system) continue;
145
+ const result = convert(value, from, abbr, origin.measure);
146
+ const { singular, plural, display } = toPlainUnit(entry);
147
+ if (!best || result >= 1 && result < best.val) {
148
+ best = { val: result, unit: abbr, singular, plural, display };
149
+ }
150
+ }
151
+ return best;
152
+ };
153
+ var getMeasures = () => Object.keys(measures);
154
+ var describe = (abbr) => toPlainUnit(getUnit(abbr) ?? throwUnsupportedUnitError(abbr, getPossibilities()));
155
+ var listUnitsWithAliases = (measure) => listUnits(measure, true);
156
+ var possibilities = (measure) => getPossibilities(measure);
157
+ var getUnitKeyByAlias = (alias) => aliasMap.get(alias);
158
+ export {
159
+ bucketMapping,
160
+ convert,
161
+ convert as default,
162
+ describe,
163
+ getMeasures,
164
+ getUnit,
165
+ getUnitForPair,
166
+ getUnitKeyByAlias,
167
+ listUnits,
168
+ listUnitsWithAliases,
169
+ possibilities,
170
+ toBest
171
+ };
172
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/loader.ts","../src/errors.ts","../src/core.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { MeasureDefinition, BucketMapping } from './types';\n\nconst UNIT_BUCKET_MAPPING_FILE = 'unitBucketMapping.json';\nconst DEFS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'definitions');\n\nconst loadDefinitions = (): Record<string, MeasureDefinition> => {\n const result: Record<string, MeasureDefinition> = {};\n const files = fs.readdirSync(DEFS_DIR).filter((f) => f.endsWith('.json') && f !== UNIT_BUCKET_MAPPING_FILE);\n\n for (const file of files) {\n const name = path.basename(file, '.json');\n const raw = JSON.parse(fs.readFileSync(path.join(DEFS_DIR, file), 'utf-8'));\n\n if (raw._anchors) {\n for (const key of Object.keys(raw._anchors)) {\n const anchor = raw._anchors[key];\n if (typeof anchor.transform === 'string') {\n anchor.transform = new Function('val', `return ${anchor.transform}`) as (val: number) => number;\n }\n }\n }\n\n result[name] = raw;\n }\n\n if (result.density) result.formationDensity = result.density;\n\n // Restore the same lookup priority as the original library.\n //\n // Measures listed here are moved to the END of the insertion order so that\n // \"first occurrence wins\" in buildIndexes() resolves shared unit keys correctly:\n //\n // density / formationDensity — share kPa/m and psi/ft with pressureGradient;\n // pressureGradient anchors must win\n // concentration — shares ppm with partsPer; partsPer must win\n // gasConcentration — shares ppm with partsPer; partsPer must win\n // force / gravity — share g with mass; mass (gram) must win\n // gasVolume — shares gal/bbl/m3 with volume; liquid anchors must win\n // spontaneousPotential — shares mV with voltage; voltage must win\n const DEPRIORITIZED = [\n 'density',\n 'formationDensity',\n 'concentration',\n 'gasConcentration',\n 'force',\n 'gravity',\n 'gasVolume',\n 'spontaneousPotential',\n ];\n const deprioritized: Record<string, MeasureDefinition> = {};\n for (const key of DEPRIORITIZED) {\n if (result[key]) {\n deprioritized[key] = result[key];\n delete result[key];\n }\n }\n return { ...result, ...deprioritized };\n};\n\nexport const measures: Record<string, MeasureDefinition> = loadDefinitions();\n\nexport const bucketMapping: BucketMapping = JSON.parse(\n fs.readFileSync(path.join(DEFS_DIR, UNIT_BUCKET_MAPPING_FILE), 'utf-8'),\n);\n","export const throwUnsupportedUnitError = (what: string, validUnits: string[]): never => {\n throw new Error(`Unsupported unit ${what}, use one of: ${validUnits.join(', ')}`);\n};\n\nexport const throwUnsupportedCompatibilityError = (abbr: string, measure: string): never => {\n throw new Error(`Unsupported compatibility for unit ${abbr} and measure ${measure}`);\n};\n\nexport const throwIncompatibleMeasuresError = (destMeasure: string, originMeasure: string): never => {\n throw new Error(`Cannot convert incompatible measures of ${destMeasure} and ${originMeasure}`);\n};\n","import { measures, bucketMapping } from './loader';\nimport {\n throwUnsupportedCompatibilityError,\n throwUnsupportedUnitError,\n throwIncompatibleMeasuresError,\n} from './errors';\nimport type { UnitDefinition, ResolvedUnit, PlainUnit, ConversionResult } from './types';\n\nconst unitIndex = new Map<string, ResolvedUnit>();\nconst measureIndex = new Map<string, ResolvedUnit[]>();\nconst aliasMap = new Map<string, string>();\n\nconst _buildIndexes = (): ResolvedUnit[] => {\n const all: ResolvedUnit[] = [];\n\n for (const [measure, systems] of Object.entries(measures)) {\n for (const [system, units] of Object.entries(systems)) {\n if (system === '_anchors') continue;\n for (const [abbr, unit] of Object.entries(units as Record<string, UnitDefinition>)) {\n const entry: ResolvedUnit = { abbr, unit, system, measure };\n all.push(entry);\n\n // First occurrence wins (preserves density over formationDensity for global lookups).\n if (!unitIndex.has(abbr)) unitIndex.set(abbr, entry);\n\n if (!measureIndex.has(measure)) measureIndex.set(measure, []);\n measureIndex.get(measure)!.push(entry);\n\n aliasMap.set(abbr, abbr);\n for (const alias of unit.aliases ?? []) aliasMap.set(alias, abbr);\n }\n }\n }\n\n return all;\n};\n\nconst allUnits = _buildIndexes();\n\n// Lookup helpers\nconst getUnit = (abbr: string, measure?: string): ResolvedUnit | undefined => {\n if (measure) {\n const entry = measureIndex.get(measure)?.find((e) => e.abbr === abbr || e.unit.aliases?.includes(abbr));\n if (!entry) throwUnsupportedCompatibilityError(abbr, measure);\n return entry;\n }\n const canonical = aliasMap.get(abbr);\n return canonical !== undefined ? unitIndex.get(canonical) : undefined;\n};\n\nconst getUnitForPair = (abbrOne: string, abbrTwo: string): [ResolvedUnit, ResolvedUnit] | null => {\n const one = unitIndex.get(abbrOne);\n const two = unitIndex.get(abbrTwo);\n return one && two && one.measure === two.measure ? [one, two] : null;\n};\n\nconst toPlainUnit = ({ abbr, measure, system, unit }: ResolvedUnit): PlainUnit => ({\n abbr,\n measure,\n system,\n singular: unit.name.singular,\n plural: unit.name.plural,\n display: unit.name.display,\n});\n\nconst _toPlainUnitWithAlias = (entry: ResolvedUnit): PlainUnit => ({\n ...toPlainUnit(entry),\n aliases: entry.unit.aliases,\n});\n\nconst listUnits = (measure?: string, withAliases = false): PlainUnit[] => {\n const decorator = withAliases ? _toPlainUnitWithAlias : toPlainUnit;\n const entries = measure ? (measureIndex.get(measure) ?? []) : allUnits;\n return entries.map(decorator);\n};\n\nconst getPossibilities = (measure?: string, origin?: ResolvedUnit): string[] => {\n const m = measure ?? origin?.measure;\n if (!m) return [...unitIndex.keys()];\n return (measureIndex.get(m) ?? []).map((e) => e.abbr);\n};\n\nconst convert = (value: number, from: string, to: string, measure?: string): number => {\n const origin = getUnit(from, measure) ?? throwUnsupportedUnitError(from, getPossibilities());\n const dest = getUnit(to, measure) ?? throwUnsupportedUnitError(to, getPossibilities());\n\n if (origin.abbr === dest.abbr) return value;\n\n let src = origin;\n let tgt = dest;\n\n if (dest.measure !== origin.measure) {\n if (measure) throwIncompatibleMeasuresError(dest.measure, origin.measure);\n [tgt, src] =\n getUnitForPair(dest.abbr, origin.abbr) ?? throwIncompatibleMeasuresError(dest.measure, origin.measure);\n }\n\n let result = value * src.unit.to_anchor;\n if (src.unit.anchor_shift) result -= src.unit.anchor_shift;\n\n if (src.system !== tgt.system) {\n const anchor = measures[src.measure]._anchors[src.system];\n result = typeof anchor.transform === 'function' ? anchor.transform(result) : result * anchor.ratio!;\n }\n\n if (tgt.unit.anchor_shift) result += tgt.unit.anchor_shift;\n return result / tgt.unit.to_anchor;\n};\n\nconst toBest = (\n value: number,\n from: string,\n measure?: string,\n exclude: string[] = [],\n): ConversionResult | undefined => {\n const origin = getUnit(from, measure);\n if (!origin) return undefined;\n\n let best: ConversionResult | undefined;\n\n for (const abbr of getPossibilities(origin.measure)) {\n if (exclude.includes(abbr)) continue;\n const entry = measureIndex.get(origin.measure)?.find((e) => e.abbr === abbr);\n if (!entry || entry.system !== origin.system) continue;\n\n const result = convert(value, from, abbr, origin.measure);\n const { singular, plural, display } = toPlainUnit(entry);\n if (!best || (result >= 1 && result < best.val)) {\n best = { val: result, unit: abbr, singular, plural, display };\n }\n }\n\n return best;\n};\n\nconst getMeasures = (): string[] => Object.keys(measures);\n\nconst describe = (abbr: string): PlainUnit =>\n toPlainUnit(getUnit(abbr) ?? throwUnsupportedUnitError(abbr, getPossibilities()));\n\nconst listUnitsWithAliases = (measure?: string): PlainUnit[] => listUnits(measure, true);\n\nconst possibilities = (measure?: string): string[] => getPossibilities(measure);\n\nconst getUnitKeyByAlias = (alias: string): string | undefined => aliasMap.get(alias);\n\nexport {\n measures,\n bucketMapping,\n aliasMap,\n getUnit,\n getUnitForPair,\n toPlainUnit,\n listUnits,\n listUnitsWithAliases,\n getMeasures,\n describe,\n possibilities,\n getUnitKeyByAlias,\n getPossibilities,\n convert,\n toBest,\n};\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@corva/convert-units",
3
+ "version": "3.1.0",
4
+ "description": "Convert between quantities in different units",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "definitions"
24
+ ],
25
+ "engines": {
26
+ "node": ">=24"
27
+ },
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "test": "node --experimental-vm-modules node_modules/.bin/jest"
31
+ },
32
+ "devDependencies": {
33
+ "@types/jest": "^29",
34
+ "@types/node": "^24",
35
+ "jest": "^30",
36
+ "ts-jest": "^29",
37
+ "tsup": "^8.5.1",
38
+ "typescript": "^5.8"
39
+ },
40
+ "author": "Corva.ai",
41
+ "license": "MIT"
42
+ }