tiny-ulid
Version:
Make and decode ULIDs.
182 lines (181 loc) • 6.62 kB
JavaScript
import { decodeUlid, getUlidBufferTime, isUlid, makeUlid, toUlidBuffer, ulidBufferToString } from "../default.js"
import { createConsola } from "consola"
const consola = createConsola({ stdout: process.stderr })
try {
const options = new Map(),
commands = []
function fatal(message) {
consola.fatal(message)
process.exit(1)
}
for (const argument of process.argv.slice(2))
if ("-" == argument[0]) {
const argumentEqualsIndex = argument.indexOf("=")
let key, value
if (-1 == argumentEqualsIndex) key = argument
else {
key = argument.slice(0, argumentEqualsIndex)
value = argument.slice(argumentEqualsIndex + 1)
}
if ("-" == argument[1]) {
const name = key.slice(2)
options.has(name) && fatal(`Option --${name} specified twice.`)
options.set(name, value)
} else
for (const name of key.slice(1)) {
options.has(name) && fatal(`Option -${name} specified twice.`)
options.set(name, value)
}
} else {
options.size && fatal("Options must come last.")
commands.push(argument)
}
consola.debug(commands)
consola.debug(options)
if ("version" == commands[0] || options.has("version")) {
console.log("1.0.0")
process.exit()
}
const poppedOptions = new Set()
let complainedAboutUnrecognisedOptions = !1
const popOption = (name, { requirePresence = !1, requireValue = !1 } = {}) => {
if (complainedAboutUnrecognisedOptions) {
consola.error(Error("Tried to pop option after already complaining"))
process.exit(2)
}
if (poppedOptions.has(name)) {
consola.error(Error(`Tried to pop option --${name} twice.`))
process.exit(2)
}
poppedOptions.add(name)
if (options.has(name)) {
const value = options.get(name)
requireValue && null == value && fatal(`Option --${name} missing value.`)
options.delete(name)
return value
}
requirePresence && fatal(`Option --${name} missing.`)
},
popFlagOption = name => {
if (complainedAboutUnrecognisedOptions) {
consola.error(Error("Tried to pop option after already complaining"))
process.exit(2)
}
if (poppedOptions.has(name)) {
consola.error(Error(`Tried to pop option --${name} twice.`))
process.exit(2)
}
poppedOptions.add(name)
if (options.has(name)) {
null != options.get(name) && fatal(`Option --${name} must not have value.`)
options.delete(name)
return !0
}
return !1
},
complainAboutUnrecognisedOptions = () => {
complainedAboutUnrecognisedOptions = !0
options.size && fatal(`Unknown option: --${options.keys().next().value}.`)
}
if (commands.length) {
if ("get-time" == commands[0]) {
commands.length < 2 && fatal("Missing argument.")
commands.length > 2 && fatal("Too many arguments.")
const ulid = commands[1]
isUlid(ulid) || fatal("Invalid ULID.")
const time = getUlidBufferTime(decodeUlid(ulid)),
formatOption = popOption("format", { requireValue: !0 })
complainAboutUnrecognisedOptions()
"locale" == formatOption || null == formatOption
? console.log(new Date(time).toLocaleString())
: "locale-full" == formatOption
? console.log(new Date(time).toLocaleString(void 0, { dateStyle: "full", timeStyle: "full" }))
: "iso" == formatOption
? console.log(new Date(time).toISOString())
: "epoch-milliseconds" == formatOption
? console.log(time + "")
: fatal(
`Unrecognised format ${JSON.stringify(formatOption)}.\nValid formats are "locale", "locale-full", "iso", and "epoch-milliseconds".`
)
process.exit()
}
if ("to-hex" == commands[0]) {
commands.length < 2 && fatal("Missing argument.")
commands.length > 2 && fatal("Too many arguments.")
const ulid = commands[1]
isUlid(ulid) || fatal("Invalid ULID.")
const ulidBuffer = decodeUlid(ulid)
consola.debug(ulidBuffer)
const lowercaseOption = popFlagOption("lowercase"),
seperator = popOption("seperator", { requireValue: !0 }) ?? " "
complainAboutUnrecognisedOptions()
const result = [...new Uint8Array(ulidBuffer)]
.map(byte => {
let result = byte.toString(16)
lowercaseOption || (result = result.toUpperCase())
return result.padStart(2, "0")
})
.join(seperator)
console.log(result)
process.exit()
}
if ("to-base64" == commands[0]) {
commands.length < 2 && fatal("Missing argument.")
commands.length > 2 && fatal("Too many arguments.")
const urlOption = popFlagOption("url")
complainAboutUnrecognisedOptions()
const ulid = commands[1]
isUlid(ulid) || fatal("Invalid ULID.")
const ulidBuffer = decodeUlid(ulid)
consola.debug(ulidBuffer)
const result = Buffer.from(ulidBuffer).toString(urlOption ? "base64url" : "base64")
console.log(result)
process.exit()
}
if ("from-hex" == commands[0]) {
commands.length < 2 && fatal("Missing argument.")
commands.length > 2 && fatal("Too many arguments.")
const hex = commands[1].replace(/\s/g, "")
hex.length < 32 && fatal("Hex too short, expected 32 hex characters.")
hex.length > 32 && fatal("Hex too long, expected 32 hex characters.")
;/^[\da-f]+$/i.test(hex) || fatal("Invalid hex.")
const buffer = Buffer.from(hex, "hex")
if (!(buffer.buffer instanceof ArrayBuffer)) {
consola.error(Error("Got " + buffer.buffer))
process.exit(2)
}
const ulidBuffer = toUlidBuffer(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.length))
console.log(ulidBufferToString(ulidBuffer))
process.exit()
}
if ("from-base64" == commands[0]) {
commands.length < 2 && fatal("Missing argument.")
commands.length > 2 && fatal("Too many arguments.")
const base64 = commands[1].replace(/[\s=]/g, "")
base64.length < 22 && fatal("Base64 too short, expected 22 base64 characters.")
base64.length > 22 && fatal("Base64 too long, expected 22 base64 characters.")
;/^[a-f\d+/-_]+$/i.test(base64) || fatal("Invalid Base64.")
"A" != base64[21] &&
"Q" != base64[21] &&
"g" != base64[21] &&
"w" != base64[21] &&
fatal('Last character of base64 can only be one of "AQgw".')
const buffer = Buffer.from(base64, "base64")
if (!(buffer.buffer instanceof ArrayBuffer)) {
consola.error(Error("Got " + buffer.buffer))
process.exit(2)
}
const ulidBuffer = toUlidBuffer(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.length))
console.log(ulidBufferToString(ulidBuffer))
process.exit()
}
fatal(`Unknown command: ${commands[0]}.`)
}
complainAboutUnrecognisedOptions()
console.log(makeUlid())
process.exit()
} catch (error) {
consola.error(error)
process.exit(2)
}