Skip to content
Merged
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
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/std@0.202.0/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