Skip to content

Commit

Permalink
feat: bidirectional unit conversion (#4)
Browse files Browse the repository at this point in the history
* fix: argument types

* ci: cache packages

* feat: bidirectional conversion

* build: do not export zod from `mod.ts`

* build: bump std to `0.208.0`
  • Loading branch information
scarf005 authored Nov 29, 2023
1 parent b7a68dc commit e2b76a9
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 882 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,13 @@ jobs:
- name: Run linter
run: deno lint

- uses: actions/cache@v3
with:
key: ${{ runner.os }}-deno-cache-${{ hashFiles('deno.lock') }}
restore-keys: ${{ runner.os }}-deno-cache-
path: |
/home/runner/.cache/deno/deps
/home/runner/.cache/deno/npm
- name: Run tests
run: deno test -A
995 changes: 143 additions & 852 deletions deno.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions deps/std/assert.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from "https://deno.land/std@0.202.0/assert/assert.ts"
export * from "https://deno.land/std@0.202.0/assert/assert_equals.ts"
export * from "https://deno.land/std@0.202.0/assert/assert_throws.ts"
export * from "https://deno.land/std@0.208.0/assert/assert.ts"
export * from "https://deno.land/std@0.208.0/assert/assert_equals.ts"
export * from "https://deno.land/std@0.208.0/assert/assert_throws.ts"
2 changes: 1 addition & 1 deletion deps/std/collection.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "https://deno.land/std@0.202.0/collections/mod.ts"
export * from "https://deno.land/std@0.208.0/collections/mod.ts"
2 changes: 1 addition & 1 deletion deps/std/fmt.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "https://deno.land/std@0.202.0/fmt/colors.ts"
export * from "https://deno.land/std@0.208.0/fmt/colors.ts"
2 changes: 1 addition & 1 deletion deps/std/fs.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "https://deno.land/std@0.202.0/fs/walk.ts"
export * from "https://deno.land/std@0.208.0/fs/walk.ts"
2 changes: 1 addition & 1 deletion deps/std/path.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "https://deno.land/std@0.202.0/path/mod.ts"
export * from "https://deno.land/std@0.208.0/path/mod.ts"
2 changes: 1 addition & 1 deletion examples/calories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const main = () =>
default: "portion" as const,
})
.description("Query food calories.")
.action(async ({ path, output, sortBy, limit, quiet = false }) => {
.action(async ({ path, output, sortBy, limit, quiet }) => {
const { timeit, timeitSync } = makeTimeits(quiet)

const filter = schemaFilter(food)
Expand Down
1 change: 0 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export { baseCli } from "./utils/cli.ts"
export { queryCli } from "./utils/query.ts"
export { z } from "./deps/zod.ts"
27 changes: 20 additions & 7 deletions units/currency.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { match } from "../deps/ts_pattern.ts"
import { match, P } from "../deps/ts_pattern.ts"
import { z } from "../deps/zod.ts"

export const currency = z.custom<`${number} ${CurrencyUnits}`>((x) =>
Expand All @@ -10,14 +10,27 @@ export type Currency = z.infer<typeof currency>
const usd = 100
const kusd = 1000 * usd

/**
* converts legacy cent to new currency format.
* @param c legacy cent (`1 unit` = `1 cent`)
* @return cent or USD or kUSD
*/
export const fromLegacyCurrency = (c: number): Currency =>
export const fromCents = (c: number): Currency =>
match(c)
.with(0, () => `0 cent` as const)
.when((c) => c % kusd === 0, () => `${c / kusd} kUSD` as const)
.when((c) => c % usd === 0, () => `${c / usd} USD` as const)
.otherwise(() => `${c} cent` as const)

export const toCents = (c: Currency): number =>
match(c)
.with(P.string.regex(/(\d+) cent/), (cent) => parseInt(cent, 10))
.with(P.string.regex(/(\d+) USD/), (USD) => parseInt(USD, 10) * usd)
.with(P.string.regex(/(\d+) kUSD/), (kUSD) => parseInt(kUSD, 10) * kusd)
.otherwise(() => 0)

/**
* converts legacy cent to new currency format.
* @param c legacy cent (`1 unit` = `1 cent`)
* @return cent or USD or kUSD
*/
export const fromLegacyCurrency = fromCents

/** multiplies currency string by given factor. */
export const multiplyCurrency = (c: Currency, n: number): Currency =>
fromCents(Math.round(toCents(c) * n))
26 changes: 20 additions & 6 deletions units/volume.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { match } from "../deps/ts_pattern.ts"
import { match, P } from "../deps/ts_pattern.ts"
import { z } from "../deps/zod.ts"

export const volume = z.custom<`${number} ${VolumeUnits}`>((x) => /^\d+ (ml|L)$/.test(x as string))
Expand All @@ -8,13 +8,27 @@ export type Volume = z.infer<typeof volume>

const litre = 1000

export const fromMililitres = (ml: number): Volume =>
match(ml)
.with(0, () => `${ml} ml` as const)
.when((ml) => ml % litre === 0, (ml) => `${ml / litre} L` as const)
.otherwise((ml) => `${ml} ml` as const)

/** converts volumes string as mililitres. */

export const toMililitres = (v: Volume): number =>
match(v)
.with(P.string.regex(/(\d+) ml/), (ml) => parseInt(ml, 10))
.with(P.string.regex(/(\d+) L/), (L) => parseInt(L, 10) * litre)
.otherwise(() => 0)

/**
* converts legacy volume to new volume format.
* @param x legacy volume (`1 unit` = `250 mL`)
* @return ml or L
*/
export const fromLegacyVolume = (x: number): Volume =>
match(x * 250)
.with(0, () => `${x} ml` as const)
.when((ml) => ml % litre === 0, (ml) => `${ml / litre} L` as const)
.otherwise((ml) => `${ml} ml` as const)
export const fromLegacyVolume = (x: number): Volume => fromMililitres(x * 250)

/** multiplies volume string by given factor. */
export const multiplyVolume = (v: Volume, n: number): Volume =>
fromMililitres(Math.round(toMililitres(v) * n))
25 changes: 20 additions & 5 deletions units/weight.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { match } from "../deps/ts_pattern.ts"
import { match, P } from "../deps/ts_pattern.ts"
import { z } from "../deps/zod.ts"

export const weight = z.custom<`${number} ${WeightUnits}`>((x) => /^\d+ (m|k)?g$/.test(x as string))
export type WeightUnits = "mg" | "g" | "kg"
export type Weight = z.infer<typeof weight>

const kilogram = 1000

export const fromGrams = (g: number): Weight =>
match(g % kilogram)
.with(0, () => `${g / 1000} kg` as const)
.otherwise(() => `${g} g` as const)

/** converts weight string as grams. */
export const toGrams = (w: Weight): number =>
match(w)
.with(P.string.regex(/(\d+) g/), (g) => parseInt(g, 10))
.with(P.string.regex(/(\d+) kg/), (kg) => parseInt(kg, 10) * kilogram)
.otherwise(() => 0)

/**
* converts legacy weight to new weight format.
* @param g legacy weight (`1 unit` = `1g`)
* @return g or kg
*/
export const fromLegacyWeight = (g: number): Weight =>
match(g % 1000)
.with(0, () => `${g / 1000} kg` as const)
.otherwise(() => `${g} g` as const)
export const fromLegacyWeight = fromGrams

/** multiplies weight string by given factor. */
export const multiplyWeight = (w: Weight, n: number): Weight =>
fromGrams(Math.round(toGrams(w) * n))
6 changes: 3 additions & 3 deletions utils/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ type OptionMethod = Command["option"]
type OptionParams = Parameters<OptionMethod>

export const cliOptions = {
path: ["-p, --path <string>", "path to recursively find jsons.", { required: true }],
quiet: ["-q, --quiet", "silence all output.", { required: false }],
output: ["-o, --output <type:string>", "output file path. outputs to stdout if omitted.", {
path: ["-p, --path <path:string>", "path to recursively find jsons.", { required: true }],
quiet: ["-q, --quiet <quiet:boolean>", "silence all output.", { default: false as const }],
output: ["-o, --output <path:string>", "output file path. outputs to stdout if omitted.", {
required: false,
}],
format: ["--format <path:string>", "format json files using formatter at given path.", {
Expand Down

0 comments on commit e2b76a9

Please sign in to comment.