@autoplay/utils
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -8,4 +8,4 @@ export * from "./internal/invariant"; | ||
export * from "./internal/pipe"; | ||
export * from "./internal/z"; | ||
export * from "./internal/z/index"; | ||
export * from "./internal/errorToString"; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,17 +0,14 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
// Invariant errors with stack trace fixing | ||
tslib_1.__exportStar(require("./internal/invariant"), exports); | ||
tslib_1.__exportStar(require("./internal/devStringify"), exports); | ||
tslib_1.__exportStar(require("./internal/DevString"), exports); | ||
tslib_1.__exportStar(require("./internal/tightJsonStringify"), exports); | ||
tslib_1.__exportStar(require("./internal/tightObjectDebug"), exports); | ||
tslib_1.__exportStar(require("./internal/staticCheck"), exports); | ||
export * from "./internal/invariant"; | ||
export * from "./internal/devStringify"; | ||
export * from "./internal/DevString"; | ||
export * from "./internal/tightJsonStringify"; | ||
export * from "./internal/tightObjectDebug"; | ||
export * from "./internal/staticCheck"; | ||
// functional pipe used for many sdk builders | ||
tslib_1.__exportStar(require("./internal/pipe"), exports); | ||
export * from "./internal/pipe"; | ||
// zod for runtime parsing for type validators (accepted and output cannot be different types) | ||
// This also includes ZodChoice type | ||
tslib_1.__exportStar(require("./internal/z"), exports); | ||
export * from "./internal/z/index"; | ||
// Error stringification including Zod types | ||
tslib_1.__exportStar(require("./internal/errorToString"), exports); | ||
export * from "./internal/errorToString"; |
@@ -10,7 +10,27 @@ /** | ||
export declare class DevString { | ||
readonly templateOrID: TemplateStringsArray | number; | ||
readonly subs: any[]; | ||
constructor(templateOrID: TemplateStringsArray | number, subs: any[]); | ||
readonly _templateOrID: TemplateStringsArray | number; | ||
readonly _subs: any[]; | ||
_values: undefined | { | ||
cause?: DevString | DevString[] | undefined; | ||
records?: Record<string, unknown>; | ||
}; | ||
constructor(_templateOrID: TemplateStringsArray | number, _subs: any[], _values?: undefined | { | ||
cause?: DevString | DevString[] | undefined; | ||
records?: Record<string, unknown>; | ||
}); | ||
/** for double clicking in */ | ||
get _json(): unknown; | ||
get _display(): unknown; | ||
/** | ||
* @example | ||
* dev`login failure`.because(reason) | ||
* dev`failed token exchange with ${issuerURL}`.because(reason) | ||
* dev`Continue button to show`.because(reason) | ||
*/ | ||
because(cause: DevString): DevString; | ||
record(key: string, value: unknown): DevString; | ||
toDisplay(): string; | ||
toString(): string; | ||
toJSON(key?: string): any[]; | ||
} | ||
//# sourceMappingURL=DevString.d.ts.map |
@@ -1,5 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DevString = exports.dev = void 0; | ||
const devStringify_1 = require("./devStringify"); | ||
import { devStringify } from "./devStringify"; | ||
/** | ||
@@ -12,19 +9,80 @@ * Future: maybe replaceable during build to create smaller packages. | ||
*/ | ||
function dev(tmpl, ...substitutions) { | ||
export function dev(tmpl, ...substitutions) { | ||
return new DevString(tmpl, substitutions); | ||
} | ||
exports.dev = dev; | ||
class DevString { | ||
constructor(templateOrID, subs) { | ||
this.templateOrID = templateOrID; | ||
this.subs = subs; | ||
export class DevString { | ||
constructor(_templateOrID, _subs, _values = undefined) { | ||
this._templateOrID = _templateOrID; | ||
this._subs = _subs; | ||
this._values = _values; | ||
} | ||
/** for double clicking in */ | ||
get _json() { | ||
return this.toJSON(); | ||
} | ||
get _display() { | ||
return this.toDisplay(); | ||
} | ||
/** | ||
* @example | ||
* dev`login failure`.because(reason) | ||
* dev`failed token exchange with ${issuerURL}`.because(reason) | ||
* dev`Continue button to show`.because(reason) | ||
*/ | ||
because(cause) { | ||
return new DevString(this._templateOrID, this._subs, { | ||
...this._values, | ||
cause: add(this._values?.cause, cause), | ||
}); | ||
} | ||
record(key, value) { | ||
return new DevString(this._templateOrID, this._subs, { | ||
...this._values, | ||
records: { | ||
...this._values?.records, | ||
[key]: value, | ||
}, | ||
}); | ||
} | ||
// Notice that `"" + {toString() { return 1}} === "1"` | ||
toDisplay() { | ||
const stringSubs = this._subs.map((sub) => devStringify(sub, true)); | ||
return typeof this._templateOrID === "number" | ||
? `#${this._templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this._templateOrID, stringSubs); | ||
} | ||
// Notice that `"" + {toString() { return 1}} === "1"` | ||
toString() { | ||
const stringSubs = this.subs.map((sub) => (0, devStringify_1.devStringify)(sub)); | ||
return typeof this.templateOrID === "number" | ||
? `#${this.templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this.templateOrID, stringSubs); | ||
const stringSubs = this._subs.map((sub) => devStringify(sub)); | ||
return typeof this._templateOrID === "number" | ||
? `#${this._templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this._templateOrID, stringSubs); | ||
} | ||
toJSON(key) { | ||
return typeof this._templateOrID === "number" | ||
? this._values == null | ||
? [this._templateOrID, ...this._subs] | ||
: [this._templateOrID, ...this._subs, this._values] | ||
: this._templateOrID.flatMap((part, idx) => idx < this._subs.length | ||
? [part, this._subs[idx]] | ||
: this._values == null | ||
? part | ||
? [part] | ||
: [] | ||
: [part, this._values]); | ||
} | ||
} | ||
exports.DevString = DevString; | ||
function add(arr, ...values) { | ||
if (values.length === 0) | ||
return arr; | ||
if (Array.isArray(values[0])) { | ||
// @ts-ignore assume that because T is array, that we default create arrays before | ||
return arr && arr.length ? [...arr, ...values] : values; | ||
} | ||
if (values.length === 1) { | ||
return arr == null ? values[0] : Array.isArray(arr) ? [...arr, values[0]] : [arr, values[0]]; | ||
} | ||
if (arr == null) | ||
return values; | ||
return Array.isArray(arr) ? [...arr, ...values] : [arr, ...values]; | ||
} |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
export declare function devStringify(input: any, indentJSON?: boolean): string; | ||
export declare function devStringify(input: any, display?: boolean): string; | ||
//# sourceMappingURL=devStringify.d.ts.map |
@@ -1,6 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.devStringify = void 0; | ||
const DevString_1 = require("./DevString"); | ||
const tightJsonStringify_1 = require("./tightJsonStringify"); | ||
import { tightJsonStringify } from "./tightJsonStringify"; | ||
/** | ||
@@ -11,13 +7,34 @@ * Stringifies any value given. If an object is given and `indentJSON` is true, | ||
*/ | ||
function devStringify(input, indentJSON = true) { | ||
export function devStringify(input, display = true) { | ||
try { | ||
return typeof input === "string" | ||
? input | ||
: typeof input === "function" || | ||
input instanceof Error || | ||
input instanceof DevString_1.DevString | ||
? input.toString() | ||
: indentJSON | ||
? (0, tightJsonStringify_1.tightJsonStringify)(input) | ||
: JSON.stringify(input); | ||
if (typeof input === "string") { | ||
if (input[0] === "{" || input[0] === "[") { | ||
try { | ||
return devStringify(JSON.parse(input), display); | ||
} | ||
catch { | ||
// I guess it wasn't JSON. No biggie! | ||
} | ||
} | ||
return input; | ||
} | ||
else if (typeof input === "function" || input instanceof Error) { | ||
return input.toString(); | ||
} | ||
else { | ||
const json = tightJsonStringify(input, (key, value) => { | ||
if (value.toJSON === undefined) { | ||
if (value instanceof Error) { | ||
return { | ||
// // @ts-ignore | ||
// cause: value.cause ?? null, | ||
error: value.toString(), | ||
stack: value.stack ?? null, | ||
}; | ||
} | ||
} | ||
return value; | ||
}); | ||
return display ? cleanNewlinesAndStacks(json.replace(/"([^"]+)":/g, "$1:")) : json; | ||
} | ||
} | ||
@@ -28,2 +45,11 @@ catch (err) { | ||
} | ||
exports.devStringify = devStringify; | ||
function cleanNewlinesAndStacks(stack) { | ||
// return stack; | ||
return stack | ||
// replace private paths before node_modules | ||
.replace(/(\(|\sat )\/[^\)\s]+node_modules\//gm, "$1node_modules/") | ||
// replace escaped newlines in strings | ||
.replace(/(.+?)"(.*\\n(.(?!\\"))+|\\")*"/gm, (_fullMatch, beforeQuote, inside) => { | ||
return beforeQuote + `"` + inside.split(/\\n/g).join("\n" + " ".repeat(beforeQuote.length)) + '"'; | ||
}); | ||
} |
@@ -1,3 +0,3 @@ | ||
import { z } from "./z"; | ||
import { z } from "./z/index"; | ||
export declare function errorToString(err: z.ZodError | any): any; | ||
//# sourceMappingURL=errorToString.d.ts.map |
@@ -1,12 +0,8 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.errorToString = void 0; | ||
const z_1 = require("./z"); | ||
function errorToString(err) { | ||
if (err instanceof z_1.z.ZodError) { | ||
import { z } from "./z/index"; | ||
export function errorToString(err) { | ||
if (err instanceof z.ZodError) { | ||
if (err.errors.length === 1) { | ||
const firstError = err.errors[0]; | ||
if (firstError.code === z_1.z.ZodIssueCode.invalid_union) { | ||
return ("\nEvery choice of union failed:\n * " + | ||
firstError.unionErrors.map((a) => a.toString()).join("\n * ")); | ||
if (firstError.code === z.ZodIssueCode.invalid_union) { | ||
return "\nEvery choice of union failed:\n * " + firstError.unionErrors.map((a) => a.toString()).join("\n * "); | ||
} | ||
@@ -18,2 +14,1 @@ } | ||
} | ||
exports.errorToString = errorToString; |
import { DevString } from "./DevString"; | ||
import { z } from "./z"; | ||
import { z } from "./z/index"; | ||
declare type AllowedMessageTypes = DevString | string | number | object; | ||
@@ -4,0 +4,0 @@ /** |
@@ -1,5 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.invariantUnreachable = exports.invariantEq = exports.invariantChoiceIs = exports.invariantThrow = exports.invariant = void 0; | ||
const devStringify_1 = require("./devStringify"); | ||
import { devStringify } from "./devStringify"; | ||
/** | ||
@@ -12,3 +9,3 @@ * invariants are like `expect` from jest or another testing library but | ||
*/ | ||
function invariant(shouldBeTruthy, message, butFoundInstead) { | ||
export function invariant(shouldBeTruthy, message, butFoundInstead) { | ||
if (!shouldBeTruthy) { | ||
@@ -24,3 +21,2 @@ const isFoundArgGiven = arguments.length > 2; | ||
} | ||
exports.invariant = invariant; | ||
/** | ||
@@ -32,13 +28,10 @@ * Throws an error message with a developer-readable and command line friendly | ||
*/ | ||
function invariantThrow(message, butFoundInstead) { | ||
export function invariantThrow(message, butFoundInstead) { | ||
const isFoundArgGiven = arguments.length > 1; | ||
const prefix = (0, devStringify_1.devStringify)(typeof message === "function" ? message() : message); | ||
const suffix = isFoundArgGiven | ||
? `\nInstead found: ${(0, devStringify_1.devStringify)(butFoundInstead)}` | ||
: ""; | ||
const prefix = devStringify(typeof message === "function" ? message() : message); | ||
const suffix = isFoundArgGiven ? `\nInstead found: ${devStringify(butFoundInstead)}` : ""; | ||
throw new InvariantError(`Invariant: ${prefix}${suffix}`, butFoundInstead); | ||
} | ||
exports.invariantThrow = invariantThrow; | ||
/** Used with our (Autoplay) custom ZodChoice */ | ||
function invariantChoiceIs(choice, key, name = "choice") { | ||
export function invariantChoiceIs(choice, key, name = "choice") { | ||
return choice.matchPartial({ [key]: identity }, (other) => { | ||
@@ -48,3 +41,2 @@ invariantThrow(`Expected ${name} to be "${key}"`, other); | ||
} | ||
exports.invariantChoiceIs = invariantChoiceIs; | ||
function identity(x) { | ||
@@ -54,3 +46,3 @@ return x; | ||
/** Asserts that the `left` strict equals the `right` */ | ||
function invariantEq(left, | ||
export function invariantEq(left, | ||
/** Pass a value for comparison */ | ||
@@ -61,7 +53,6 @@ right, | ||
if (left !== right) | ||
throw new InvariantError(`Invariant expected ${(0, devStringify_1.devStringify)(left, false)} = ${(0, devStringify_1.devStringify)(right, false)}` + | ||
throw new InvariantError(`Invariant expected ${devStringify(left, false)} = ${devStringify(right, false)}` + | ||
optionalMessageSuffix(message) + | ||
(arguments.length > 3 ? `\nInstead found: ${(0, devStringify_1.devStringify)(found)}` : ""), found); | ||
(arguments.length > 3 ? `\nInstead found: ${devStringify(found)}` : ""), found); | ||
} | ||
exports.invariantEq = invariantEq; | ||
/** | ||
@@ -83,11 +74,7 @@ * Enable exhaustive checking | ||
*/ | ||
function invariantUnreachable(x, message) { | ||
invariantThrow("invariantUnreachable encountered value which was supposed to be never" + | ||
optionalMessageSuffix(message), x); | ||
export function invariantUnreachable(x, message) { | ||
invariantThrow("invariantUnreachable encountered value which was supposed to be never" + optionalMessageSuffix(message), x); | ||
} | ||
exports.invariantUnreachable = invariantUnreachable; | ||
function optionalMessageSuffix(message) { | ||
return message | ||
? " in " + (0, devStringify_1.devStringify)(typeof message === "function" ? message() : message) | ||
: ""; | ||
return message ? " in " + devStringify(typeof message === "function" ? message() : message) : ""; | ||
} | ||
@@ -114,11 +101,13 @@ // regexes to remove lines from thrown error stacktraces | ||
// prettier-ignore | ||
this.stack = this.stack | ||
?.replace(AT_INVARIANT_RE, "") | ||
.replace(AT_INVARIANT_MORE_RE, "") | ||
.replace(AT_TYPES_INTERNAL_RE, "") | ||
.replace(AT_ASSORTED_HELPERS_RE, "") | ||
.replace(AT_TEST_HELPERS_RE, "") | ||
.replace(AT_NODE_INTERNAL_RE, ""); | ||
// console.error({ before, after: this.stack }) | ||
if (this.stack) { | ||
this.stack = this.stack | ||
.replace(AT_INVARIANT_RE, "") | ||
.replace(AT_INVARIANT_MORE_RE, "") | ||
.replace(AT_TYPES_INTERNAL_RE, "") | ||
.replace(AT_ASSORTED_HELPERS_RE, "") | ||
.replace(AT_TEST_HELPERS_RE, "") | ||
.replace(AT_NODE_INTERNAL_RE, ""); | ||
// console.error({ before, after: this.stack }) | ||
} | ||
} | ||
} |
@@ -1,5 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.pipe = void 0; | ||
function pipe(a, ...fns) { | ||
export function pipe(a, ...fns) { | ||
// Could have used reduce, but for loops are faster, have a bit nicer stacktrace, and are easier to place breakpoints into | ||
@@ -12,2 +9,1 @@ // `return fns.reduce((x, fn) => fn(x), a)` | ||
} | ||
exports.pipe = pipe; |
@@ -1,4 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.staticCheck = void 0; | ||
/** | ||
@@ -12,5 +9,4 @@ * Static check "identity" function which should be used to indicate | ||
*/ | ||
function staticCheck(x) { | ||
export function staticCheck(x) { | ||
return x; | ||
} | ||
exports.staticCheck = staticCheck; |
@@ -1,4 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.tightJsonStringify = void 0; | ||
/** | ||
@@ -25,3 +22,3 @@ * Stringifies an object in a developer-readable, command line friendly way | ||
*/ | ||
function tightJsonStringify(obj, replacer) { | ||
export function tightJsonStringify(obj, replacer) { | ||
return JSON.stringify(obj, replacer, 2) | ||
@@ -32,2 +29,1 @@ .replace(/^([\{\[])\n (\s+)/, "$1$2") | ||
} | ||
exports.tightJsonStringify = tightJsonStringify; |
@@ -1,7 +0,4 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.tightObjectDebug = void 0; | ||
const tightJsonStringify_1 = require("./tightJsonStringify"); | ||
function tightObjectDebug(obj) { | ||
return (0, tightJsonStringify_1.tightJsonStringify)(obj, (key, value) => { | ||
import { tightJsonStringify } from "./tightJsonStringify"; | ||
export function tightObjectDebug(obj) { | ||
return tightJsonStringify(obj, (key, value) => { | ||
if (value instanceof Map) { | ||
@@ -16,2 +13,1 @@ return Object.fromEntries(value.entries()); | ||
} | ||
exports.tightObjectDebug = tightObjectDebug; |
@@ -1,4 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.z = void 0; | ||
exports.z = require("./z"); | ||
export * as z from "./z"; |
@@ -0,7 +1,6 @@ | ||
import * as z from "zod"; | ||
export * from "zod"; | ||
import * as z from "zod"; | ||
export { ZodChoice, choiceType as choice } from "./zchoice"; | ||
export { ZodChoiceContainer, ZodChoiceVariantsToValue, ZodChoiceFactory, inferChoiceContainer, } from "./zchoice"; | ||
export { optionType as option } from "./zoption"; | ||
export { ZodOption } from "./zoption"; | ||
export { ZodChoiceContainer, ZodChoiceVariantsToValue, ZodChoiceFactory, inferChoiceContainer } from "./zchoice"; | ||
export { optionType as option, ZodOption } from "./zoption"; | ||
export declare const obj: typeof z.object; | ||
@@ -8,0 +7,0 @@ /** |
@@ -1,16 +0,9 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.or = exports.unchecked = exports.obj = exports.option = exports.ZodChoiceContainer = exports.choice = void 0; | ||
const tslib_1 = require("tslib"); | ||
tslib_1.__exportStar(require("zod"), exports); | ||
const z = require("zod"); | ||
const staticCheck_1 = require("../staticCheck"); | ||
import { staticCheck } from "../staticCheck"; | ||
import * as z from "zod"; | ||
export * from "zod"; | ||
// Custom Zod types | ||
var zchoice_1 = require("./zchoice"); | ||
Object.defineProperty(exports, "choice", { enumerable: true, get: function () { return zchoice_1.choiceType; } }); | ||
var zchoice_2 = require("./zchoice"); | ||
Object.defineProperty(exports, "ZodChoiceContainer", { enumerable: true, get: function () { return zchoice_2.ZodChoiceContainer; } }); | ||
var zoption_1 = require("./zoption"); | ||
Object.defineProperty(exports, "option", { enumerable: true, get: function () { return zoption_1.optionType; } }); | ||
exports.obj = z.object.bind(z); | ||
export { choiceType as choice } from "./zchoice"; | ||
export { ZodChoiceContainer } from "./zchoice"; | ||
export { optionType as option } from "./zoption"; | ||
export const obj = z.object.bind(z); | ||
/** | ||
@@ -22,6 +15,5 @@ * Enables creating a zod type which works purely during static | ||
*/ | ||
function unchecked() { | ||
return z.custom(staticCheck_1.staticCheck); | ||
export function unchecked() { | ||
return z.custom(staticCheck); | ||
} | ||
exports.unchecked = unchecked; | ||
/** | ||
@@ -33,3 +25,3 @@ * A more permissive version of `z.union`. | ||
*/ | ||
function or(...items) { | ||
export function or(...items) { | ||
if (items.length > 1) | ||
@@ -40,2 +32,1 @@ return z.union([items[0], items[1], ...items.slice(2)]); | ||
} | ||
exports.or = or; |
@@ -1,6 +0,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.choiceType = exports.ZodChoiceContainer = void 0; | ||
const z = require("zod"); | ||
class ZodChoiceContainer { | ||
import * as z from "zod"; | ||
export class ZodChoiceContainer { | ||
// @internal | ||
@@ -12,3 +9,2 @@ constructor(match, matchPartial) { | ||
} | ||
exports.ZodChoiceContainer = ZodChoiceContainer; | ||
/** | ||
@@ -22,3 +18,3 @@ * enum-ts for zod types | ||
*/ | ||
function choiceType(variantNameToZodType) { | ||
export function choiceType(variantNameToZodType) { | ||
const variantNames = Object.keys(variantNameToZodType); | ||
@@ -115,2 +111,1 @@ const unexpected = `Unexpected variant unmatched. Expected one of ${variantNames | ||
} | ||
exports.choiceType = choiceType; |
@@ -0,3 +1,3 @@ | ||
import { ZodChoice } from "./zchoice"; | ||
import * as z from "zod"; | ||
import { ZodChoice } from "./zchoice"; | ||
export declare type ZodOption<T> = { | ||
@@ -4,0 +4,0 @@ Some: T; |
@@ -1,8 +0,5 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.optionType = void 0; | ||
const z = require("zod"); | ||
const zchoice_1 = require("./zchoice"); | ||
function optionType(some) { | ||
return (0, zchoice_1.choiceType)({ | ||
import { choiceType } from "./zchoice"; | ||
import * as z from "zod"; | ||
export function optionType(some) { | ||
return choiceType({ | ||
Some: some, | ||
@@ -12,2 +9,1 @@ None: z.literal(true), | ||
} | ||
exports.optionType = optionType; |
{ | ||
"name": "@autoplay/utils", | ||
"version": "0.0.6", | ||
"description": "", | ||
"version": "0.0.7", | ||
"description": "Utilities designed for error management, parsing, and TypeScript domain modeling.", | ||
"keywords": [], | ||
"type": "module", | ||
"main": "dist/index.js", | ||
@@ -12,3 +13,3 @@ "types": "dist/index.d.ts", | ||
"test": "jest", | ||
"prepack": "npm run clean && npm run build" | ||
"prepare": "npm run clean && npm run build" | ||
}, | ||
@@ -33,3 +34,2 @@ "files": [ | ||
"@swc/jest": "^0.2.22", | ||
"@types/node": "^18.6.1", | ||
"jest": "^28.1.3", | ||
@@ -41,2 +41,2 @@ "rimraf": "^3.0.2", | ||
} | ||
} | ||
} |
@@ -12,4 +12,4 @@ // Invariant errors with stack trace fixing | ||
// This also includes ZodChoice type | ||
export * from "./internal/z"; | ||
export * from "./internal/z/index"; | ||
// Error stringification including Zod types | ||
export * from "./internal/errorToString"; |
@@ -10,6 +10,3 @@ import { devStringify } from "./devStringify"; | ||
*/ | ||
export function dev( | ||
tmpl: TemplateStringsArray, | ||
...substitutions: any[] | ||
): DevString { | ||
export function dev(tmpl: TemplateStringsArray, ...substitutions: any[]): DevString { | ||
return new DevString(tmpl, substitutions); | ||
@@ -20,13 +17,83 @@ } | ||
constructor( | ||
public readonly templateOrID: TemplateStringsArray | number, | ||
public readonly subs: any[] | ||
public readonly _templateOrID: TemplateStringsArray | number, | ||
public readonly _subs: any[], | ||
public _values: undefined | { cause?: DevString | DevString[] | undefined; records?: Record<string, unknown> } = undefined, | ||
) {} | ||
/** for double clicking in */ | ||
get _json(): unknown { | ||
return this.toJSON(); | ||
} | ||
get _display(): unknown { | ||
return this.toDisplay(); | ||
} | ||
/** | ||
* @example | ||
* dev`login failure`.because(reason) | ||
* dev`failed token exchange with ${issuerURL}`.because(reason) | ||
* dev`Continue button to show`.because(reason) | ||
*/ | ||
because(cause: DevString): DevString { | ||
return new DevString(this._templateOrID, this._subs, { | ||
...this._values, | ||
cause: add(this._values?.cause, cause), | ||
}); | ||
} | ||
record(key: string, value: unknown): DevString { | ||
return new DevString(this._templateOrID, this._subs, { | ||
...this._values, | ||
records: { | ||
...this._values?.records, | ||
[key]: value, | ||
}, | ||
}); | ||
} | ||
// Notice that `"" + {toString() { return 1}} === "1"` | ||
toDisplay() { | ||
const stringSubs = this._subs.map((sub) => devStringify(sub, true)); | ||
return typeof this._templateOrID === "number" | ||
? `#${this._templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this._templateOrID as TemplateStringsArray, stringSubs); | ||
} | ||
// Notice that `"" + {toString() { return 1}} === "1"` | ||
toString() { | ||
const stringSubs = this.subs.map((sub) => devStringify(sub)); | ||
return typeof this.templateOrID === "number" | ||
? `#${this.templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this.templateOrID as TemplateStringsArray, stringSubs); | ||
const stringSubs = this._subs.map((sub) => devStringify(sub)); | ||
return typeof this._templateOrID === "number" | ||
? `#${this._templateOrID}: ${stringSubs.join("; ")}` // if dev calls are replaced with message identifiers (this is speculative) | ||
: String.raw(this._templateOrID as TemplateStringsArray, stringSubs); | ||
} | ||
toJSON(key?: string) { | ||
return typeof this._templateOrID === "number" | ||
? this._values == null | ||
? [this._templateOrID, ...this._subs] | ||
: [this._templateOrID, ...this._subs, this._values] | ||
: this._templateOrID.flatMap((part, idx) => | ||
idx < this._subs.length | ||
? [part, this._subs[idx]] | ||
: this._values == null | ||
? part | ||
? [part] | ||
: [] | ||
: [part, this._values], | ||
); | ||
} | ||
} | ||
function add<T>(arr: undefined | T | T[], ...values: T[]): undefined | T | T[] { | ||
if (values.length === 0) return arr; | ||
if (Array.isArray(values[0])) { | ||
// @ts-ignore assume that because T is array, that we default create arrays before | ||
return arr && arr.length ? [...arr, ...values] : values; | ||
} | ||
if (values.length === 1) { | ||
return arr == null ? values[0] : Array.isArray(arr) ? [...arr, values[0]] : [arr, values[0]]; | ||
} | ||
if (arr == null) return values; | ||
return Array.isArray(arr) ? [...arr, ...values] : [arr, ...values]; | ||
} |
import { DevString } from "./DevString"; | ||
import { tightJsonStringify } from "./tightJsonStringify"; | ||
import { quotelessJson } from "zod"; | ||
@@ -9,13 +10,32 @@ /** | ||
*/ | ||
export function devStringify(input: any, indentJSON: boolean = true): string { | ||
export function devStringify(input: any, display: boolean = true): string { | ||
try { | ||
return typeof input === "string" | ||
? input | ||
: typeof input === "function" || | ||
input instanceof Error || | ||
input instanceof DevString | ||
? input.toString() | ||
: indentJSON | ||
? tightJsonStringify(input) | ||
: JSON.stringify(input); | ||
if (typeof input === "string") { | ||
if (input[0] === "{" || input[0] === "[") { | ||
try { | ||
return devStringify(JSON.parse(input), display); | ||
} catch { | ||
// I guess it wasn't JSON. No biggie! | ||
} | ||
} | ||
return input; | ||
} else if (typeof input === "function" || input instanceof Error) { | ||
return input.toString(); | ||
} else { | ||
const json = tightJsonStringify(input, (key, value) => { | ||
if (value.toJSON === undefined) { | ||
if (value instanceof Error) { | ||
return { | ||
// // @ts-ignore | ||
// cause: value.cause ?? null, | ||
error: value.toString(), | ||
stack: value.stack ?? null, | ||
}; | ||
} | ||
} | ||
return value; | ||
}); | ||
return display ? cleanNewlinesAndStacks(json.replace(/"([^"]+)":/g, "$1:")) : json; | ||
} | ||
} catch (err) { | ||
@@ -25,1 +45,12 @@ return input?.name || String(input); | ||
} | ||
function cleanNewlinesAndStacks(stack: string): string { | ||
// return stack; | ||
return stack | ||
// replace private paths before node_modules | ||
.replace(/(\(|\sat )\/[^\)\s]+node_modules\//gm, "$1node_modules/") | ||
// replace escaped newlines in strings | ||
.replace(/(.+?)"(.*\\n(.(?!\\"))+|\\")*"/gm, (_fullMatch, beforeQuote, inside) => { | ||
return beforeQuote + `"` + inside.split(/\\n/g).join("\n" + " ".repeat(beforeQuote.length)) + '"'; | ||
}); | ||
} |
@@ -1,2 +0,2 @@ | ||
import { z } from "./z"; | ||
import { z } from "./z/index"; | ||
@@ -8,6 +8,3 @@ export function errorToString(err: z.ZodError | any) { | ||
if (firstError.code === z.ZodIssueCode.invalid_union) { | ||
return ( | ||
"\nEvery choice of union failed:\n * " + | ||
firstError.unionErrors.map((a) => a.toString()).join("\n * ") | ||
); | ||
return "\nEvery choice of union failed:\n * " + firstError.unionErrors.map((a) => a.toString()).join("\n * "); | ||
} | ||
@@ -14,0 +11,0 @@ } |
import { DevString } from "./DevString"; | ||
import { devStringify } from "./devStringify"; | ||
import { z } from "./z"; | ||
import { z } from "./z/index"; | ||
@@ -17,3 +17,3 @@ type AllowedMessageTypes = DevString | string | number | object; | ||
message: (() => AllowedMessageTypes) | AllowedMessageTypes, | ||
butFoundInstead?: any | ||
butFoundInstead?: any, | ||
): asserts shouldBeTruthy { | ||
@@ -38,11 +38,7 @@ if (!shouldBeTruthy) { | ||
message: (() => AllowedMessageTypes) | AllowedMessageTypes, | ||
butFoundInstead?: any | ||
butFoundInstead?: any, | ||
): never { | ||
const isFoundArgGiven = arguments.length > 1; | ||
const prefix = devStringify( | ||
typeof message === "function" ? message() : message | ||
); | ||
const suffix = isFoundArgGiven | ||
? `\nInstead found: ${devStringify(butFoundInstead)}` | ||
: ""; | ||
const prefix = devStringify(typeof message === "function" ? message() : message); | ||
const suffix = isFoundArgGiven ? `\nInstead found: ${devStringify(butFoundInstead)}` : ""; | ||
throw new InvariantError(`Invariant: ${prefix}${suffix}`, butFoundInstead); | ||
@@ -54,8 +50,4 @@ } | ||
TVariants extends Record<string, any>, | ||
VariantName extends Extract<keyof TVariants, string> | ||
>( | ||
choice: z.ZodChoiceContainer<TVariants>, | ||
key: VariantName, | ||
name = "choice" | ||
): TVariants[VariantName] { | ||
VariantName extends Extract<keyof TVariants, string>, | ||
>(choice: z.ZodChoiceContainer<TVariants>, key: VariantName, name = "choice"): TVariants[VariantName] { | ||
return choice.matchPartial({ [key]: identity } as Partial<any>, (other) => { | ||
@@ -77,13 +69,10 @@ invariantThrow(`Expected ${name} to be "${key}"`, other); | ||
message?: (() => AllowedMessageTypes) | AllowedMessageTypes, | ||
found?: any | ||
found?: any, | ||
) { | ||
if (left !== right) | ||
throw new InvariantError( | ||
`Invariant expected ${devStringify(left, false)} = ${devStringify( | ||
right, | ||
false | ||
)}` + | ||
optionalMessageSuffix(message) + | ||
(arguments.length > 3 ? `\nInstead found: ${devStringify(found)}` : ""), | ||
found | ||
`Invariant expected ${devStringify(left, false)} = ${devStringify(right, false)}` + | ||
optionalMessageSuffix(message) + | ||
(arguments.length > 3 ? `\nInstead found: ${devStringify(found)}` : ""), | ||
found, | ||
); | ||
@@ -108,10 +97,6 @@ } | ||
*/ | ||
export function invariantUnreachable( | ||
x: never, | ||
message?: AllowedMessageTypes | ||
): never { | ||
export function invariantUnreachable(x: never, message?: AllowedMessageTypes): never { | ||
invariantThrow( | ||
"invariantUnreachable encountered value which was supposed to be never" + | ||
optionalMessageSuffix(message), | ||
x | ||
"invariantUnreachable encountered value which was supposed to be never" + optionalMessageSuffix(message), | ||
x, | ||
); | ||
@@ -121,5 +106,3 @@ } | ||
function optionalMessageSuffix(message?: AllowedMessageTypes): string { | ||
return message | ||
? " in " + devStringify(typeof message === "function" ? message() : message) | ||
: ""; | ||
return message ? " in " + devStringify(typeof message === "function" ? message() : message) : ""; | ||
} | ||
@@ -134,4 +117,3 @@ | ||
// const AT_WEB_MODULES = /^\s*(at|[^@]+@).+(web_modules|\-[a-f0-9]{8}\.js).*/gm | ||
const AT_ASSORTED_HELPERS_RE = | ||
/^\s*(at|[^@]+@).+(debounce|invariant|iif)\.[tj]s.*/gm; | ||
const AT_ASSORTED_HELPERS_RE = /^\s*(at|[^@]+@).+(debounce|invariant|iif)\.[tj]s.*/gm; | ||
@@ -151,11 +133,13 @@ /** | ||
// prettier-ignore | ||
this.stack = this.stack | ||
?.replace(AT_INVARIANT_RE, "") | ||
.replace(AT_INVARIANT_MORE_RE, "") | ||
.replace(AT_TYPES_INTERNAL_RE, "") | ||
.replace(AT_ASSORTED_HELPERS_RE, "") | ||
.replace(AT_TEST_HELPERS_RE, "") | ||
.replace(AT_NODE_INTERNAL_RE, "") | ||
// console.error({ before, after: this.stack }) | ||
if (this.stack) { | ||
this.stack = this.stack | ||
.replace(AT_INVARIANT_RE, "") | ||
.replace(AT_INVARIANT_MORE_RE, "") | ||
.replace(AT_TYPES_INTERNAL_RE, "") | ||
.replace(AT_ASSORTED_HELPERS_RE, "") | ||
.replace(AT_TEST_HELPERS_RE, "") | ||
.replace(AT_NODE_INTERNAL_RE, "") | ||
// console.error({ before, after: this.stack }) | ||
} | ||
} | ||
} |
@@ -0,28 +1,25 @@ | ||
import { tightJsonStringify } from "./tightJsonStringify"; | ||
import { describe, expect, it } from "@jest/globals"; | ||
import { tightJsonStringify } from "./tightJsonStringify"; | ||
describe("tightJsonStringify", () => { | ||
it("matches a series of expectations", () => { | ||
expect(tightJsonStringify({ a: 1, b: 2, c: { y: 4, z: 745 } })) | ||
.toMatchInlineSnapshot(` | ||
"{ \\"a\\": 1, | ||
\\"b\\": 2, | ||
\\"c\\": { | ||
\\"y\\": 4, | ||
\\"z\\": 745 } }" | ||
expect(tightJsonStringify({ a: 1, b: 2, c: { y: 4, z: 745 } })).toMatchInlineSnapshot(` | ||
"{ "a": 1, | ||
"b": 2, | ||
"c": { | ||
"y": 4, | ||
"z": 745 } }" | ||
`); | ||
expect(tightJsonStringify(true)).toMatchInlineSnapshot(`"true"`); | ||
expect(tightJsonStringify("Already a string")).toMatchInlineSnapshot( | ||
`"\\"Already a string\\""` | ||
); | ||
expect(tightJsonStringify({ a: 1, b: { c: [1, 2, { d: 4 }], e: 8 } })) | ||
.toMatchInlineSnapshot(` | ||
"{ \\"a\\": 1, | ||
\\"b\\": { | ||
\\"c\\": [ | ||
expect(tightJsonStringify("Already a string")).toMatchInlineSnapshot(`""Already a string""`); | ||
expect(tightJsonStringify({ a: 1, b: { c: [1, 2, { d: 4 }], e: 8 } })).toMatchInlineSnapshot(` | ||
"{ "a": 1, | ||
"b": { | ||
"c": [ | ||
1, | ||
2, | ||
{ \\"d\\": 4 } ], | ||
\\"e\\": 8 } }" | ||
{ "d": 4 } ], | ||
"e": 8 } }" | ||
`); | ||
}); | ||
}); |
@@ -22,6 +22,3 @@ /** | ||
*/ | ||
export function tightJsonStringify( | ||
obj: any, | ||
replacer?: ((this: any, key: string, value: any) => any) | undefined | ||
) { | ||
export function tightJsonStringify(obj: any, replacer?: ((this: any, key: string, value: any) => any) | undefined) { | ||
return JSON.stringify(obj, replacer, 2) | ||
@@ -28,0 +25,0 @@ .replace(/^([\{\[])\n (\s+)/, "$1$2") |
@@ -1,15 +0,10 @@ | ||
export * from "zod"; | ||
import { staticCheck } from "../staticCheck"; | ||
import * as z from "zod"; | ||
import { staticCheck } from "../staticCheck"; | ||
export * from "zod"; | ||
// Custom Zod types | ||
export { ZodChoice, choiceType as choice } from "./zchoice"; | ||
export { | ||
ZodChoiceContainer, | ||
ZodChoiceVariantsToValue, | ||
ZodChoiceFactory, | ||
inferChoiceContainer, | ||
} from "./zchoice"; | ||
export { optionType as option } from "./zoption"; | ||
export { ZodOption } from "./zoption"; | ||
export { ZodChoiceContainer, ZodChoiceVariantsToValue, ZodChoiceFactory, inferChoiceContainer } from "./zchoice"; | ||
export { optionType as option, ZodOption } from "./zoption"; | ||
@@ -34,7 +29,5 @@ export const obj: typeof z.object = z.object.bind(z); | ||
*/ | ||
export function or<T extends Array<z.ZodTypeAny>>( | ||
...items: T | ||
): z.ZodType<T[number]["_type"]> { | ||
export function or<T extends Array<z.ZodTypeAny>>(...items: T): z.ZodType<T[number]["_type"]> { | ||
if (items.length > 1) return z.union([items[0], items[1], ...items.slice(2)]); | ||
else return items[0]; | ||
} |
@@ -0,3 +1,3 @@ | ||
import { choiceType, ZodChoice } from "./zchoice"; | ||
import * as z from "zod"; | ||
import { choiceType, ZodChoice } from "./zchoice"; | ||
@@ -14,3 +14,3 @@ export type ZodOption<T> = | ||
export function optionType<T extends z.ZodTypeAny>( | ||
some: T | ||
some: T, | ||
): ZodChoice<{ | ||
@@ -17,0 +17,0 @@ Some: T; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
82922
8
56
1698
Yes