feat(ulid): add single-export endpoints (#5426)

This commit is contained in:
Yoshiya Hinosawa 2024-07-12 16:48:01 +09:00 committed by GitHub
parent 94fff63978
commit 0f4ff71948
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 156 additions and 134 deletions

2
.github/typos.toml vendored
View File

@ -16,5 +16,5 @@ extend-exclude = [
"media_types/vendor",
"http/testdata",
"http/user_agent.ts",
"ulid/mod.ts"
"ulid/*.ts"
]

53
ulid/decode_time.ts Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright 2023 Yoshiya Hinosawa. All rights reserved. MIT license.
// Copyright 2017 Alizain Feerasta. All rights reserved. MIT license.
// This module is browser compatible.
import {
ENCODING,
ENCODING_LEN,
TIME_LEN,
TIME_MAX,
ULID_LEN,
} from "./_util.ts";
/**
* Extracts the number of milliseconds since the Unix epoch that had passed when
* the ULID was generated. If the ULID is malformed, an error will be thrown.
*
* @example Decode the time from a ULID
* ```ts
* import { decodeTime, ulid } from "@std/ulid";
* import { assertEquals } from "@std/assert";
*
* const timestamp = 150_000;
* const ulidString = ulid(timestamp);
*
* assertEquals(decodeTime(ulidString), timestamp);
* ```
*
* @param ulid The ULID to extract the timestamp from.
* @returns The number of milliseconds since the Unix epoch that had passed when the ULID was generated.
*/
export function decodeTime(ulid: string): number {
if (ulid.length !== ULID_LEN) {
throw new Error(`ULID must be exactly ${ULID_LEN} characters long`);
}
const time = ulid
.substring(0, TIME_LEN)
.split("")
.reverse()
.reduce((carry, char, index) => {
const encodingIndex = ENCODING.indexOf(char);
if (encodingIndex === -1) {
throw new Error(`Invalid ULID character found: ${char}`);
}
return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
}, 0);
if (time > TIME_MAX) {
throw new RangeError(
`ULID timestamp component exceeds maximum value of ${TIME_MAX}`,
);
}
return time;
}

View File

@ -1,5 +1,10 @@
{
"name": "@std/ulid",
"version": "1.0.0-rc.3",
"exports": "./mod.ts"
"exports": {
".": "./mod.ts",
"./decoce-time": "./decode_time.ts",
"./monotonic-ulid": "./monotonic_ulid.ts",
"./ulid": "./ulid.ts"
}
}

View File

@ -44,135 +44,6 @@
* @module
*/
import {
encodeRandom,
encodeTime,
ENCODING,
ENCODING_LEN,
monotonicFactory,
TIME_LEN,
TIME_MAX,
ULID_LEN,
} from "./_util.ts";
/**
* Extracts the number of milliseconds since the Unix epoch that had passed when
* the ULID was generated. If the ULID is malformed, an error will be thrown.
*
* @example Decode the time from a ULID
* ```ts
* import { decodeTime, ulid } from "@std/ulid";
* import { assertEquals } from "@std/assert";
*
* const timestamp = 150_000;
* const ulidString = ulid(timestamp);
*
* assertEquals(decodeTime(ulidString), timestamp);
* ```
*
* @param ulid The ULID to extract the timestamp from.
* @returns The number of milliseconds since the Unix epoch that had passed when the ULID was generated.
*/
export function decodeTime(ulid: string): number {
if (ulid.length !== ULID_LEN) {
throw new Error(`ULID must be exactly ${ULID_LEN} characters long`);
}
const time = ulid
.substring(0, TIME_LEN)
.split("")
.reverse()
.reduce((carry, char, index) => {
const encodingIndex = ENCODING.indexOf(char);
if (encodingIndex === -1) {
throw new Error(`Invalid ULID character found: ${char}`);
}
return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
}, 0);
if (time > TIME_MAX) {
throw new RangeError(
`ULID timestamp component exceeds maximum value of ${TIME_MAX}`,
);
}
return time;
}
const defaultMonotonicUlid = monotonicFactory();
/**
* Generate a ULID that monotonically increases even for the same millisecond,
* optionally passing the current time. If the current time is not passed, it
* will default to `Date.now()`.
*
* Unlike the {@linkcode ulid} function, this function is guaranteed to return
* strictly increasing ULIDs, even for the same seed time, but only if the seed
* time only ever increases. If the seed time ever goes backwards, the ULID will
* still be generated, but it will not be guaranteed to be monotonic with
* previous ULIDs for that same seed time.
*
* @example Generate a monotonic ULID
* ```ts no-assert
* import { monotonicUlid } from "@std/ulid";
*
* monotonicUlid(); // 01HYFKHG5F8RHM2PM3D7NSTDAS
* monotonicUlid(); // 01HYFKHG5F8RHM2PM3D7NSTDAT
* monotonicUlid(); // 01HYFKHHX8H4BRY8BYHAV1BZ2T
* ```
*
* @example Generate a monotonic ULID with a seed time
* ```ts no-assert
* import { monotonicUlid } from "@std/ulid";
*
* // Strict ordering for the same timestamp, by incrementing the least-significant random bit by 1
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1Q
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1R
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1S
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1T
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1U
*
* // A different timestamp will reset the random bits
* monotonicUlid(150001); // 0000004JFHJJ2Z7X64FN2B4F1P
*
* // A previous seed time will not guarantee ordering, and may result in a
* // ULID lower than one with the same seed time generated previously
* monotonicUlid(150000); // 0000004JFJ7XF6D76ES95SZR0X
* ```
*
* @param seedTime The time to base the ULID on, in milliseconds since the Unix epoch. Defaults to `Date.now()`.
* @returns A ULID that is guaranteed to be strictly increasing for the same seed time.
*/
export function monotonicUlid(seedTime: number = Date.now()): string {
return defaultMonotonicUlid(seedTime);
}
/**
* Generate a ULID, optionally based on a given timestamp. If the timestamp is
* not passed, it will default to `Date.now()`.
*
* Multiple calls to this function with the same seed time will not guarantee
* that the ULIDs will be strictly increasing, even if the seed time is the
* same. For that, use the {@linkcode monotonicUlid} function.
*
* @example Generate a ULID
* ```ts no-assert
* import { ulid } from "@std/ulid";
*
* ulid(); // 01HYFKMDF3HVJ4J3JZW8KXPVTY
* ulid(); // 01HYFKMDF3D2P7G502B9Z2VKV0
* ulid(); // 01HYFKMDZQ7JD17CRKDXQSZ3Z4
* ```
*
* @example Generate a ULID with a seed time
* ```ts no-assert
* import { ulid } from "@std/ulid";
*
* ulid(150000); // 0000004JFG3EKDRE04TVVDJW7K
* ulid(150000); // 0000004JFGN0KHBH0447AK895X
* ulid(150000); // 0000004JFGMRDH0PN7SM8BZN06
* ```
*
* @param seedTime The time to base the ULID on, in milliseconds since the Unix epoch. Defaults to `Date.now()`.
* @returns A ULID.
*/
export function ulid(seedTime: number = Date.now()): string {
return encodeTime(seedTime) + encodeRandom();
}
export * from "./decode_time.ts";
export * from "./monotonic_ulid.ts";
export * from "./ulid.ts";

54
ulid/monotonic_ulid.ts Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright 2023 Yoshiya Hinosawa. All rights reserved. MIT license.
// Copyright 2017 Alizain Feerasta. All rights reserved. MIT license.
// This module is browser compatible.
import { monotonicFactory } from "./_util.ts";
const defaultMonotonicUlid = monotonicFactory();
/**
* Generate a ULID that monotonically increases even for the same millisecond,
* optionally passing the current time. If the current time is not passed, it
* will default to `Date.now()`.
*
* Unlike the {@linkcode ulid} function, this function is guaranteed to return
* strictly increasing ULIDs, even for the same seed time, but only if the seed
* time only ever increases. If the seed time ever goes backwards, the ULID will
* still be generated, but it will not be guaranteed to be monotonic with
* previous ULIDs for that same seed time.
*
* @example Generate a monotonic ULID
* ```ts no-assert
* import { monotonicUlid } from "@std/ulid";
*
* monotonicUlid(); // 01HYFKHG5F8RHM2PM3D7NSTDAS
* monotonicUlid(); // 01HYFKHG5F8RHM2PM3D7NSTDAT
* monotonicUlid(); // 01HYFKHHX8H4BRY8BYHAV1BZ2T
* ```
*
* @example Generate a monotonic ULID with a seed time
* ```ts no-assert
* import { monotonicUlid } from "@std/ulid";
*
* // Strict ordering for the same timestamp, by incrementing the least-significant random bit by 1
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1Q
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1R
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1S
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1T
* monotonicUlid(150000); // 0000004JFHJJ2Z7X64FN2B4F1U
*
* // A different timestamp will reset the random bits
* monotonicUlid(150001); // 0000004JFHJJ2Z7X64FN2B4F1P
*
* // A previous seed time will not guarantee ordering, and may result in a
* // ULID lower than one with the same seed time generated previously
* monotonicUlid(150000); // 0000004JFJ7XF6D76ES95SZR0X
* ```
*
* @param seedTime The time to base the ULID on, in milliseconds since the Unix epoch. Defaults to `Date.now()`.
* @returns A ULID that is guaranteed to be strictly increasing for the same seed time.
*/
export function monotonicUlid(seedTime: number = Date.now()): string {
return defaultMonotonicUlid(seedTime);
}

39
ulid/ulid.ts Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright 2023 Yoshiya Hinosawa. All rights reserved. MIT license.
// Copyright 2017 Alizain Feerasta. All rights reserved. MIT license.
// This module is browser compatible.
import { encodeRandom, encodeTime } from "./_util.ts";
/**
* Generate a ULID, optionally based on a given timestamp. If the timestamp is
* not passed, it will default to `Date.now()`.
*
* Multiple calls to this function with the same seed time will not guarantee
* that the ULIDs will be strictly increasing, even if the seed time is the
* same. For that, use the {@linkcode monotonicUlid} function.
*
* @example Generate a ULID
* ```ts no-assert
* import { ulid } from "@std/ulid";
*
* ulid(); // 01HYFKMDF3HVJ4J3JZW8KXPVTY
* ulid(); // 01HYFKMDF3D2P7G502B9Z2VKV0
* ulid(); // 01HYFKMDZQ7JD17CRKDXQSZ3Z4
* ```
*
* @example Generate a ULID with a seed time
* ```ts no-assert
* import { ulid } from "@std/ulid";
*
* ulid(150000); // 0000004JFG3EKDRE04TVVDJW7K
* ulid(150000); // 0000004JFGN0KHBH0447AK895X
* ulid(150000); // 0000004JFGMRDH0PN7SM8BZN06
* ```
*
* @param seedTime The time to base the ULID on, in milliseconds since the Unix epoch. Defaults to `Date.now()`.
* @returns A ULID.
*/
export function ulid(seedTime: number = Date.now()): string {
return encodeTime(seedTime) + encodeRandom();
}