Skip to content

Commit

Permalink
Merge pull request #40 from lambdalisue/predicate-name
Browse files Browse the repository at this point in the history
👍 Add name property to type predicate functions
  • Loading branch information
lambdalisue authored Sep 23, 2023
2 parents 905643c + 4dd37e5 commit 019fd38
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 29 deletions.
45 changes: 45 additions & 0 deletions __snapshots__/inspect_test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export const snapshot = {};

snapshot[`inspect > string 1`] = `'"hello world"'`;

snapshot[`inspect > number 1`] = `"100"`;

snapshot[`inspect > bigint 1`] = `"100n"`;

snapshot[`inspect > boolean 1`] = `"true"`;

snapshot[`inspect > array 1`] = `"[]"`;

snapshot[`inspect > array 2`] = `"[0, 1, 2]"`;

snapshot[`inspect > array 3`] = `'[0, "a", true]'`;

snapshot[`inspect > array 4`] = `"[0, [1, [2]]]"`;

snapshot[`inspect > record 1`] = `"{}"`;

snapshot[`inspect > record 2`] = `"{a: 0, b: 1, c: 2}"`;

snapshot[`inspect > record 3`] = `
'{
a: "a",
b: 1,
c: true
}'
`;

snapshot[`inspect > record 4`] = `"{a: {b: {c: 0}}}"`;

snapshot[`inspect > function 1`] = `"inspect"`;

snapshot[`inspect > function 2`] = `"(anonymous)"`;

snapshot[`inspect > null 1`] = `"null"`;

snapshot[`inspect > undefined 1`] = `"undefined"`;

snapshot[`inspect > symbol 1`] = `"Symbol(a)"`;

snapshot[`inspect > date 1`] = `"Date"`;

snapshot[`inspect > promise 1`] = `"Promise"`;
92 changes: 92 additions & 0 deletions __snapshots__/is_test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
export const snapshot = {};

snapshot[`isArrayOf<T> > returns properly named function 1`] = `"isArrayOf(isNumber)"`;
snapshot[`isArrayOf<T> > returns properly named function 2`] = `"isArrayOf((anonymous))"`;
snapshot[`isTupleOf<T> > returns properly named function 1`] = `
"isTupleOf([
isNumber,
isString,
isBoolean
])"
`;
snapshot[`isTupleOf<T> > returns properly named function 2`] = `"isTupleOf([(anonymous)])"`;
snapshot[`isTupleOf<T> > returns properly named function 3`] = `
"isTupleOf([
isTupleOf([
isTupleOf([
isNumber,
isString,
isBoolean
])
])
])"
`;
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber)"`;
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous))"`;
snapshot[`isObjectOf<T> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
b: isString,
c: isBoolean
})"
`;
snapshot[`isObjectOf<T> > returns properly named function 2`] = `"isObjectOf({a: a})"`;
snapshot[`isObjectOf<T> > returns properly named function 3`] = `
"isObjectOf({
a: isObjectOf({
b: isObjectOf({c: isBoolean})
})
})"
`;
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
snapshot[`isLiteralOf<T> > returns properly named function 1`] = `'isLiteralOf("hello")'`;
snapshot[`isLiteralOf<T> > returns properly named function 2`] = `"isLiteralOf(100)"`;
snapshot[`isLiteralOf<T> > returns properly named function 3`] = `"isLiteralOf(100n)"`;
snapshot[`isLiteralOf<T> > returns properly named function 4`] = `"isLiteralOf(true)"`;
snapshot[`isLiteralOf<T> > returns properly named function 5`] = `"isLiteralOf(null)"`;
snapshot[`isLiteralOf<T> > returns properly named function 6`] = `"isLiteralOf(undefined)"`;
snapshot[`isLiteralOf<T> > returns properly named function 7`] = `"isLiteralOf(Symbol(asdf))"`;
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
snapshot[`isOneOf<T> > returns properly named function 1`] = `
"isOneOf([
isNumber,
isString,
isBoolean
])"
`;
snapshot[`isAllOf<T> > returns properly named function 1`] = `
"isAllOf([
isObjectOf({a: isNumber}),
isObjectOf({b: isString})
])"
`;
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
59 changes: 59 additions & 0 deletions inspect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const defaultThreshold = 20;

export type InspectOptions = {
// The maximum number of characters of a single attribute
threshold?: number;
};

/**
* Inspect a value
*/
export function inspect(value: unknown, options: InspectOptions = {}): string {
if (value === null) {
return "null";
} else if (Array.isArray(value)) {
return inspectArray(value, options);
}
switch (typeof value) {
case "string":
return JSON.stringify(value);
case "bigint":
return `${value}n`;
case "object":
if (value.constructor?.name !== "Object") {
return value.constructor?.name;
}
return inspectRecord(value as Record<PropertyKey, unknown>, options);
case "function":
return value.name || "(anonymous)";
}
return value?.toString() ?? "undefined";
}

function inspectArray(value: unknown[], options: InspectOptions): string {
const { threshold = defaultThreshold } = options;
const vs = value.map((v) => inspect(v, options));
const s = vs.join(", ");
if (s.length <= threshold) return `[${s}]`;
const m = vs.join(",\n");
return `[\n${indent(2, m)}\n]`;
}

function inspectRecord(
value: Record<PropertyKey, unknown>,
options: InspectOptions,
): string {
const { threshold = defaultThreshold } = options;
const vs = Object.entries(value).map(([k, v]) =>
`${k}: ${inspect(v, options)}`
);
const s = vs.join(", ");
if (s.length <= threshold) return `{${s}}`;
const m = vs.join(",\n");
return `{\n${indent(2, m)}\n}`;
}

function indent(level: number, text: string): string {
const prefix = " ".repeat(level);
return text.split("\n").map((line) => `${prefix}${line}`).join("\n");
}
50 changes: 50 additions & 0 deletions inspect_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
assertSnapshot,
} from "https://deno.land/[email protected]/testing/snapshot.ts";
import { inspect } from "./inspect.ts";

Deno.test("inspect", async (t) => {
await t.step("string", async (t) => {
await assertSnapshot(t, inspect("hello world"));
});
await t.step("number", async (t) => {
await assertSnapshot(t, inspect(100));
});
await t.step("bigint", async (t) => {
await assertSnapshot(t, inspect(100n));
});
await t.step("boolean", async (t) => {
await assertSnapshot(t, inspect(true));
});
await t.step("array", async (t) => {
await assertSnapshot(t, inspect([]));
await assertSnapshot(t, inspect([0, 1, 2]));
await assertSnapshot(t, inspect([0, "a", true]));
await assertSnapshot(t, inspect([0, [1, [2]]]));
});
await t.step("record", async (t) => {
await assertSnapshot(t, inspect({}));
await assertSnapshot(t, inspect({ a: 0, b: 1, c: 2 }));
await assertSnapshot(t, inspect({ a: "a", b: 1, c: true }));
await assertSnapshot(t, inspect({ a: { b: { c: 0 } } }));
});
await t.step("function", async (t) => {
await assertSnapshot(t, inspect(inspect));
await assertSnapshot(t, inspect(() => {}));
});
await t.step("null", async (t) => {
await assertSnapshot(t, inspect(null));
});
await t.step("undefined", async (t) => {
await assertSnapshot(t, inspect(undefined));
});
await t.step("symbol", async (t) => {
await assertSnapshot(t, inspect(Symbol("a")));
});
await t.step("date", async (t) => {
await assertSnapshot(t, inspect(new Date()));
});
await t.step("promise", async (t) => {
await assertSnapshot(t, inspect(new Promise(() => {})));
});
});
Loading

0 comments on commit 019fd38

Please sign in to comment.