Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 76 additions & 31 deletions impl/ts/src/uxid.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,92 @@
const CROCKFORD_ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
const INVALID_REGEX = new RegExp(`[^${CROCKFORD_ENCODING}]`)
const TIME_MAX = Math.pow(2, 48) - 1
const TIME_LEN = 10
const CrockfordEncoding = [
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F",
"G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "V", "W", "X", "Y", "Z"
]

class UXID {
encoded: string;
time: number;
encoded: string
prefix: string
randSize: number
randEncoded: string
time: number
timeEncoded: string

static decode(encoded: string): UXID {
if (!encoded || encoded === "") {
throw "input is required"
}
static generate(prefix?: string, size?: string): string {
let uxid = new UXID(prefix, size)
return uxid.encoded
}

constructor(prefix?: string, size?: string) {
this.prefix = prefix
this.time = (new Date).valueOf()

switch (size) {
case "xs":
case "xsmall":
this.randSize = 0;
break;

case "s":
case "small":
this.randSize = 2;
break;

case "m":
case "medium":
this.randSize = 5;
break;

case "l":
case "large":
this.randSize = 7;
break;

if (encoded.match(INVALID_REGEX)) {
throw `expected input to be a Base32 encoded string, got: '${encoded}'`
default:
this.randSize = 10;
}

let uxid = new UXID(encoded)
uxid.decode()
return uxid
this.encode()
}

static generate(): string {
return "UXID"
}
encode(): void {
this.encodeTime()
this.encodeRand()

let binEncoded = this.timeEncoded + this.randEncoded

constructor(encoded?: string, time?: number) {
this.encoded = encoded
this.time = time
if (this.prefix) {
this.encoded = this.prefix + "_" + binEncoded
} else {
this.encoded = binEncoded
}
}

decode(): void {
this.decodeTime()
encodeTime(): void {
let timeArray = new Uint8Array(6)
let timeView = new DataView(timeArray.buffer, 0, 6)
let timeChars = new Array(10)

timeView.setUint16(0, (this.time / 4294967296.0) | 0);
timeView.setUint32(2, this.time | 0);

timeChars[0] = CrockfordEncoding[(timeArray[0]&224)>>5]
timeChars[1] = CrockfordEncoding[timeArray[0]&31]
timeChars[2] = CrockfordEncoding[(timeArray[1]&248)>>3]
timeChars[3] = CrockfordEncoding[((timeArray[1]&7)<<2)|((timeArray[2]&192)>>6)]
timeChars[4] = CrockfordEncoding[(timeArray[2]&62)>>1]
timeChars[5] = CrockfordEncoding[((timeArray[2]&1)<<4)|((timeArray[3]&240)>>4)]
timeChars[6] = CrockfordEncoding[((timeArray[3]&15)<<1)|((timeArray[4]&128)>>7)]
timeChars[7] = CrockfordEncoding[(timeArray[4]&124)>>2]
timeChars[8] = CrockfordEncoding[((timeArray[4]&3)<<3)|((timeArray[5]&224)>>5)]
timeChars[9] = CrockfordEncoding[timeArray[5]&31]

this.timeEncoded = timeChars.join("")
}

decodeTime(): void {
this.time = this.encoded
.substr(0, TIME_LEN)
.split("")
.reverse()
.reduce((carry, char, index) => {
return (carry += CROCKFORD_ENCODING.indexOf(char) * Math.pow(32, index))
}, 0)
encodeRand(): string {
let randEncoded = "rrrrrrrrrrrrrrrr"
this.randEncoded = randEncoded
return this.randEncoded
}
}

Expand Down
38 changes: 0 additions & 38 deletions impl/ts/test/spec/0001-setup-api.test.ts

This file was deleted.

42 changes: 0 additions & 42 deletions impl/ts/test/spec/0101-basic-decoding.test.ts

This file was deleted.

34 changes: 33 additions & 1 deletion impl/ts/test/uxid.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
"use strict";
var UXID = require("../src/uxid").UXID
import UXID from "../src/uxid"

test("UXID", () => {
expect(UXID).not.toBeNull()
})

test("UXID.generate()", () => {
const uxid = UXID.generate()

expect(uxid).not.toBeNull()
expect(uxid.length).toBe(26)
})

test("UXID.generate(\"cus\")", () => {
const uxid = UXID.generate("cus")

expect(uxid).not.toBeNull()
expect(uxid.length).toBe(30)
})

/*
test("UXID.generate(\"cus\", \"xs\")", () => {
const uxid = UXID.generate("cus", "xs")
console.log(uxid)

expect(uxid).not.toBeNull()
expect(uxid.length).toBe(14)
})

test("UXID.generate(\"cus\", \"xl\")", () => {
const uxid = UXID.generate("cus", "xl")
console.log(uxid)

expect(uxid).not.toBeNull()
expect(uxid.length).toBe(30)
})
*/