Skip to content
This repository has been archived by the owner on Apr 2, 2023. It is now read-only.

Commit

Permalink
feat: pass non-PII values through methods
Browse files Browse the repository at this point in the history
  • Loading branch information
tdreyno committed Mar 5, 2021
1 parent d61d279 commit b460577
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 20 deletions.
File renamed without changes.
8 changes: 8 additions & 0 deletions src/__tests__/fold.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ describe("fold", () => {
const folded = fold((sum, n) => sum + n, 0, [one, two, three])
expect(unwrap(folded)).toBe(6)
})

it("should fold mixed PII", () => {
const one = PII(1)
const two = 2
const three = PII(3)
const folded = fold((sum, n) => sum + n, 0, [one, two, three])
expect(unwrap(folded)).toBe(6)
})
})
6 changes: 6 additions & 0 deletions src/__tests__/map.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ describe("map", () => {
const mapped = map(a => a.toLowerCase(), result)
expect(unwrap(mapped)).toBe("test_string")
})

it("should map non PII as well", () => {
const result = "TEST_STRING"
const mapped = map(a => a.toLowerCase(), result)
expect(unwrap(mapped)).toBe("test_string")
})
})
10 changes: 10 additions & 0 deletions src/__tests__/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,14 @@ describe("test", () => {
const isIt = test(a => a.includes("sprang"), result)
expect(isIt).toBeFalsy()
})

it("should also test predicate against non-PII", () => {
const resultA = ["TEST_STRING"]
const isItA = test(Array.isArray, resultA)
expect(isItA).toBeTruthy()

const resultB = "TEST_STRING"
const isItB = test(a => a.includes("sprang"), resultB)
expect(isItB).toBeFalsy()
})
})
4 changes: 4 additions & 0 deletions src/__tests__/unwrap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ describe("unwrap", () => {
it("upwraps a value", () => {
expect(unwrap(PII("test"))).toBe("test")
})

it("should map non PII as well", () => {
expect(unwrap("test")).toBe("test")
})
})
35 changes: 35 additions & 0 deletions src/__tests__/zipWith.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ describe("zipWith", () => {
expect(unwrap(zipped)).toBe("three 3")
})

it("should zipWith two mixed types of PII", () => {
const name = PII("three")
const three = 3
const zipped = zip2With((a, b) => `${a} ${b}`, name, three)
expect(unwrap(zipped)).toBe("three 3")
})

it("should zipWith three different types of PII", () => {
const name = PII("three")
const three = PII(3)
Expand All @@ -21,6 +28,19 @@ describe("zipWith", () => {
expect(unwrap(zipped)).toBe("three 3 false")
})

it("should zipWith three mixed types of PII", () => {
const name = PII("three")
const three = PII(3)
const nope = false
const zipped = zip3With(
(a, b, c) => `${a} ${b} ${c ? "true" : "false"}`,
name,
three,
nope,
)
expect(unwrap(zipped)).toBe("three 3 false")
})

it("should zipWith four different types of PII", () => {
const name = PII("three")
const three = PII(3)
Expand All @@ -35,4 +55,19 @@ describe("zipWith", () => {
)
expect(unwrap(zipped)).toBe("three 3 false six")
})

it("should zipWith four mixed types of PII", () => {
const name = PII("three")
const three = PII(3)
const nope = PII(false)
const who = "six"
const zipped = zip4With(
(a, b, c, d) => `${a} ${b} ${c ? "true" : "false"} ${d}`,
name,
three,
nope,
who,
)
expect(unwrap(zipped)).toBe("three 3 false six")
})
})
57 changes: 37 additions & 20 deletions src/pii.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// Class which wraps PII and keeps logging from accessing it.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface PII<T> {
Expand All @@ -19,48 +20,64 @@ export const PII = <T>(val: T): PII<T> =>
toJSON: () => "PII<REDACTED>",
} as PII<T>)

export const unwrap = <A>(item: PII<A>): A =>
export function unwrap<T>(item: PII<T>): Exclude<T, PII<any>>
export function unwrap<T>(item: T): Exclude<T, PII<any>>
export function unwrap<T>(item: T | PII<T>): Exclude<T, PII<any>> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item as any)[
"__fire_me_if_you_see_me_accessing_this_property_outside_pii_ts"
]
return isPIIType(item)
? (item as any)[
"__fire_me_if_you_see_me_accessing_this_property_outside_pii_ts"
]
: item
}

export const map = <T, T2>(fn: (item: T) => T2, item: PII<T>): PII<T2> =>
PII(fn(unwrap(item)))
export function map<T, T2>(fn: (item: T) => T2, item: PII<T>): PII<T2>
export function map<T, T2>(fn: (item: T) => T2, item: T): Exclude<T2, PII<any>>
export function map<T, T2>(
fn: (item: T) => T2,
item: PII<T> | T,
): PII<T2> | Exclude<T2, PII<any>> {
return PII(fn(unwrap(item)))
}

export const test = <T>(fn: (item: T) => boolean, item: PII<T>): boolean =>
fn(unwrap(item))
export function test<T>(fn: (item: T) => boolean, item: PII<T>): boolean
export function test<T>(fn: (item: T) => boolean, item: T): boolean
export function test<T>(fn: (item: T) => boolean, item: PII<T> | T): boolean {
return fn(unwrap(item))
}

export const fold = <A, B>(
export function fold<A, B>(
fn: (
previousValue: B,
currentValue: A,
currentIndex: number,
array: A[],
) => B,
initial: B,
a: Array<PII<A>>,
): PII<B> => PII(a.map(unwrap).reduce(fn, initial))
a: Array<PII<A> | A>,
): PII<B> {
return PII(a.map<A>(unwrap).reduce(fn, initial))
}

export const zip2With = <A, B, C>(
fn: (a: A, b: B) => C,
a: PII<A>,
b: PII<B>,
a: PII<A> | A,
b: PII<B> | B,
): PII<C> => PII(fn(unwrap(a), unwrap(b)))

export const zip3With = <A, B, C, D>(
fn: (a: A, b: B, c: C) => D,
a: PII<A>,
b: PII<B>,
c: PII<C>,
a: PII<A> | A,
b: PII<B> | B,
c: PII<C> | C,
): PII<D> => PII(fn(unwrap(a), unwrap(b), unwrap(c)))

export const zip4With = <A, B, C, D, E>(
fn: (a: A, b: B, c: C, d: D) => E,
a: PII<A>,
b: PII<B>,
c: PII<C>,
d: PII<D>,
a: PII<A> | A,
b: PII<B> | B,
c: PII<C> | C,
d: PII<D> | D,
): PII<E> => PII(fn(unwrap(a), unwrap(b), unwrap(c), unwrap(d)))

const proto = Object.prototype
Expand Down

0 comments on commit b460577

Please sign in to comment.