diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 001ce9a..24300ef 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ permissions: contents: read jobs: - test-deno: + test-on-deno-and-lint: runs-on: ${{ matrix.os }} timeout-minutes: 5 strategy: @@ -27,7 +27,6 @@ jobs: - ubuntu-latest - windows-latest - macOS-latest - steps: - name: Set line ending for Windows if: matrix.os == 'windows-latest' @@ -42,14 +41,90 @@ jobs: deno-version: canary - name: Install dependencies - run: deno install + run: deno install --vendor - name: Format & Check run: deno run check - # - name: Test - # run: deno task test + - name: Test + run: deno test - name: Publish dry run run: deno publish --dry-run if: matrix.os == 'ubuntu-latest' + + test-on-bun: + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + - macOS-latest + steps: + - name: Set line ending for Windows + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf false + + - name: Clone repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Bun version + run: bun --version + + - name: Install JSR dependencies + run: bunx jsr add @cross/test @std/assert + + - name: Install NPM dependencies + run: bun add luxon + + - name: Test + run: bun test + + test-on-node: + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + strategy: + fail-fast: false + matrix: + node-version: + - 20 + - 22 + - 23 + os: + - ubuntu-latest + - windows-latest + - macOS-latest + steps: + - name: Set line ending for Windows + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf false + + - name: Clone repository + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install JSR dependencies + run: npx jsr add @cross/test @std/assert + + - name: Install NPM dependencies + run: npm install luxon + + - name: Node version + run: node --version + + - name: Set up package.json + run: 'echo ''{ "type": "module" }'' > package.json' + + - name: Test + run: npx --yes tsx --test **/*.test.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ab0b93 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.DS_Store +coverage/ + +# config +keys/* +.env + +# Dependency directories +node_modules/ + +tmp diff --git a/dates/dates.test.ts b/dates/dates.test.ts new file mode 100644 index 0000000..ddf7a69 --- /dev/null +++ b/dates/dates.test.ts @@ -0,0 +1,101 @@ +import { test } from '@cross/test' +import { assert, assertEquals } from '@std/assert' +import { + DateTime, + getDateHourMinutes, + getFullRelativeTime, + getISO, + getIso, + getMs, + getMsOffset, + getNow, + getRelative, + getUnix, + getYearMonthDay, + msToUnix, + parseISO, + parseIso, + toLocal, +} from './dates.ts' + +test('toLocal() converts date to Amsterdam timezone', () => { + const utcDate = DateTime.fromISO('2024-03-15T12:00:00Z') + const localDate = toLocal(utcDate) + assertEquals(localDate.zoneName, 'Europe/Amsterdam') +}) + +test('msToUnix() converts milliseconds to unix timestamp', () => { + const ms = 1647345600000 + assertEquals(msToUnix(ms), 1647345600) +}) + +test('getNow() returns current DateTime', () => { + const now = getNow() + assert(now instanceof DateTime) + assert(Math.abs(now.toMillis() - Date.now()) < 1000) // Within 1 second +}) + +test('getUnix() returns unix timestamp', () => { + const now = DateTime.fromMillis(1647345600000) // March 15, 2024 12:00:00 UTC + assertEquals(getUnix(now), 1647345600) +}) + +test('getMs() returns millisecond timestamp', () => { + const now = DateTime.fromMillis(1647345600000) // March 15, 2024 12:00:00 UTC + assertEquals(getMs(now), 1647345600000) +}) + +test('getISO() returns ISO string in UTC', () => { + const date = DateTime.fromISO('2024-03-15T12:00:00+01:00') + assertEquals(getISO(date), '2024-03-15T11:00:00.000Z') +}) + +test('getIso() is an alias for getISO()', () => { + const date = DateTime.fromISO('2024-03-15T12:00:00+01:00') + assertEquals(getIso(date), getISO(date)) +}) + +test('getMsOffset() calculates offset from previous timestamp', () => { + const now = getMs() + const earlier = now - 1000 // 1 second ago + assert(getMsOffset(earlier) >= 1000) +}) + +test('getRelative() returns relative time string', () => { + const now = getNow() + const yesterday = now.minus({ days: 1 }) + assertEquals(getRelative(yesterday), '1 day ago') +}) + +test('getYearMonthDay() formats date correctly', () => { + const date = DateTime.fromISO('2024-03-15T12:00:00Z') + assertEquals(getYearMonthDay(date), 20240315) + assertEquals(getYearMonthDay(date, true), '2024-03-15') +}) + +test('parseISO() parses ISO string correctly', () => { + const isoString = '2024-03-15T12:00:00.000Z' + const parsed = parseISO(isoString) + assert(parsed instanceof DateTime) + assertEquals(parsed.toUTC().toISO(), isoString) +}) + +test('parseIso() is an alias for parseISO()', () => { + const isoString = '2024-03-15T12:00:00.000Z' + assertEquals(parseIso(isoString).toISO(), parseISO(isoString).toISO()) +}) + +test('getDateHourMinutes() formats date in human readable way', () => { + const date = DateTime.fromISO('2024-03-15T12:00:00Z') + const formatted = getDateHourMinutes(date) + assert(formatted.includes('Mar')) + assert(formatted.includes('2024')) +}) + +test('getFullRelativeTime() combines date and relative time', () => { + const date = DateTime.fromISO('2024-03-15T12:00:00Z') + const fullRelative = getFullRelativeTime(date) + assert(fullRelative.includes('Mar')) + assert(fullRelative.includes('2024')) + assert(fullRelative.includes('ago')) +}) diff --git a/dates/dates.ts b/dates/dates.ts index 398fb28..c55f852 100644 --- a/dates/dates.ts +++ b/dates/dates.ts @@ -1,7 +1,8 @@ // load package import { DateTime } from 'luxon' -const localTimeZone = 'Europe/Amsterdam' +const LOCAL_TIMEZONE = 'Europe/Amsterdam' +const DATE_HOUR_MINUTES_FORMAT = 'ccc, d. LLLL yyyy - h:mma' /** * Luxon DateTime @@ -20,7 +21,7 @@ export { DateTime } * toLocal(getNow()) * ``` */ -export const toLocal = (date: DateTime): DateTime => date.setZone(localTimeZone) +export const toLocal = (date: DateTime): DateTime => date.setZone(LOCAL_TIMEZONE) /** * Converts ms timestamp to s @@ -182,7 +183,6 @@ export const parseIso = parseISO * getDateHourMinutes(getNow()) * ``` */ -const DATE_HOUR_MINUTES_FORMAT = 'ccc, d. LLLL yyyy - h:mma' export const getDateHourMinutes = (date: DateTime): string => `${date.setLocale('en').toFormat(DATE_HOUR_MINUTES_FORMAT)}` diff --git a/deno.jsonc b/deno.jsonc index cd83705..fc3772c 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -32,6 +32,8 @@ "workspace": ["./check-required-env", "./dates", "./logger"], "imports": { "@biomejs/biome": "npm:@biomejs/biome@^1.9.4", - "@types/node": "npm:@types/node@^22.9.0" + "@types/node": "npm:@types/node@^22.9.0", + "@cross/test": "jsr:@cross/test@0.0.9", + "@std/assert": "jsr:@std/assert@^0.218.2" } } diff --git a/deno.lock b/deno.lock index 68922a4..55396e1 100644 --- a/deno.lock +++ b/deno.lock @@ -1,7 +1,11 @@ { "version": "4", "specifiers": { + "jsr:@cross/runtime@1": "1.1.0", + "jsr:@cross/test@0.0.9": "0.0.9", "jsr:@frytg/logger@0.0.2": "0.0.2", + "jsr:@std/assert@~0.218.2": "0.218.2", + "jsr:@std/fmt@~0.218.2": "0.218.2", "npm:@biomejs/biome@1.9.4": "1.9.4", "npm:@biomejs/biome@^1.9.4": "1.9.4", "npm:@types/node@*": "22.5.4", @@ -10,11 +14,29 @@ "npm:winston@^3.17.0": "3.17.0" }, "jsr": { + "@cross/runtime@1.1.0": { + "integrity": "f35a3b768a9de125277329483b684062ffc9ee86f4449cb8b3d614adcad64ffb" + }, + "@cross/test@0.0.9": { + "integrity": "2aa8237a96a2f8f51ccc8fec71135616d223bf4f38dd89ba4f863037c85ddc56", + "dependencies": [ + "jsr:@cross/runtime" + ] + }, "@frytg/logger@0.0.2": { "integrity": "dc62281aa498bb33e55084a8bdbf90893ea5d82d4628828ff810f6746d3bfcc5", "dependencies": [ "npm:winston" ] + }, + "@std/assert@0.218.2": { + "integrity": "7f0a5a1a8cf86607cd6c2c030584096e1ffad27fc9271429a8cb48cfbdee5eaf", + "dependencies": [ + "jsr:@std/fmt" + ] + }, + "@std/fmt@0.218.2": { + "integrity": "99526449d2505aa758b6cbef81e7dd471d8b28ec0dcb1491d122b284c548788a" } }, "npm": { @@ -224,7 +246,43 @@ ] } }, + "redirects": { + "https://deno.land/std/assert/mod.ts": "https://deno.land/std@0.224.0/assert/mod.ts" + }, "remote": { + "https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", + "https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", + "https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7", + "https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74", + "https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", + "https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", + "https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46", + "https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b", + "https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", + "https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", + "https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68", + "https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3", + "https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", + "https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", + "https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", + "https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", + "https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8", + "https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", + "https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", + "https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5", + "https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", + "https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", + "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", + "https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", + "https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", + "https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", + "https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", + "https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", + "https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5", + "https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6", + "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", + "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e", "https://esm.sh/@bunny.net/edgescript-sdk@0.11.2": "7732aa338bf5f0c7d13e294c15833416d4bad59807de874c59f36c1f81acd935", "https://esm.sh/jsr/@hono/hono@4.6.10": "cf6e6ff70376b2ed1dc2c03b0ea0e0ddb94a750b9924731c8c1f355d028cffb2", "https://esm.sh/jsr/@hono/hono@4.6.10/cors": "dc14db48bfb6d71008ebfd7c8eb51aa46b7b3e0f505348fca3693d3fdd32abe1", @@ -247,6 +305,8 @@ }, "workspace": { "dependencies": [ + "jsr:@cross/test@0.0.9", + "jsr:@std/assert@~0.218.2", "npm:@biomejs/biome@^1.9.4", "npm:@types/node@^22.9.0" ],