From 4a964b260203a9c573da32ee9e689442df60adb0 Mon Sep 17 00:00:00 2001 From: Antonio Stoilkov Date: Thu, 8 Feb 2024 10:43:53 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=F0=9F=94=80=20new=20`options.wrap`?= =?UTF-8?q?=20property=20that's=20more=20powerful=20with=20`auto`,=20`sing?= =?UTF-8?q?le-line`,=20`multi-line`=20or=20`number`=20for=20line=20breakin?= =?UTF-8?q?g=20+=20old=20`options.lineLength`=20is=20now=20removed=20in=20?= =?UTF-8?q?favor=20of=20`options.wrap`=20+=20`consoleTable()`=20now=20show?= =?UTF-8?q?s=20as=20much=20of=20the=20object=20inline=20as=20it=20can=20+?= =?UTF-8?q?=20removed=20`consoleGroup()`=20usage=20when=20object=20is=20at?= =?UTF-8?q?=20root=20level?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extras/consoleTable.ts | 4 +- src/extras/consoleTable/consoleTableCell.ts | 84 ++++++++++++------- .../consoleTable/flatObjectOrArrayTable.ts | 2 +- src/inspect/consoleInspect.ts | 46 +++++----- src/inspect/inspectors/inspectAny.ts | 7 +- src/inspect/inspectors/inspectArray.ts | 38 ++++----- .../inspectors/inspectInline.ts} | 10 +-- src/inspect/inspectors/inspectObject.ts | 30 ++++--- ...tLineLength.ts => guessAvailableLength.ts} | 2 +- src/utils/spansLength.ts | 11 ++- 10 files changed, 141 insertions(+), 93 deletions(-) rename src/{utils/consoleInline.ts => inspect/inspectors/inspectInline.ts} (57%) rename src/utils/{defaultLineLength.ts => guessAvailableLength.ts} (90%) diff --git a/src/extras/consoleTable.ts b/src/extras/consoleTable.ts index 19f6393..541dcf9 100644 --- a/src/extras/consoleTable.ts +++ b/src/extras/consoleTable.ts @@ -1,7 +1,7 @@ import { ConsoleText } from "../core/consoleText"; import hasOnlyPrimitives from "../utils/hasOnlyPrimitives"; import consolePrint from "../core/consolePrint"; -import defaultLineLength from "../utils/defaultLineLength"; +import guessAvailableLength from "../utils/guessAvailableLength"; import arrayOfObjectsTable from "./consoleTable/arrayOfObjectsTable"; import flatObjectOrArrayTable from "./consoleTable/flatObjectOrArrayTable"; @@ -19,7 +19,7 @@ export default function consoleTable( Array.isArray(object) && !hasOnlyPrimitives(object); const optionsRequired = { print: true, - lineLength: defaultLineLength(), + lineLength: guessAvailableLength(), theme: matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light", diff --git a/src/extras/consoleTable/consoleTableCell.ts b/src/extras/consoleTable/consoleTableCell.ts index a1e9980..b8d8916 100644 --- a/src/extras/consoleTable/consoleTableCell.ts +++ b/src/extras/consoleTable/consoleTableCell.ts @@ -1,38 +1,66 @@ -import consoleInline from "../../utils/consoleInline"; +import inspectInline from "../../inspect/inspectors/inspectInline"; import inspectAny from "../../inspect/inspectors/inspectAny"; import { ConsoleText, consoleText } from "../../core/consoleText"; import createTableCell, { ConsoleTableCell } from "./createTableCell"; +import spansLength from "../../utils/spansLength"; export default function consoleTableCell( value: unknown, theme: "light" | "dark", maxCellLength: number, ): ConsoleTableCell { - const spans = inspectAny( - value, - { - theme, - lineLength: maxCellLength, - print: false, - line: false, - indent: 0, - depth: 2, - }, - { - depth: 1, - indent: 0, - }, - ).map((span) => { - return typeof span === "string" - ? consoleText(span) - : span.type === "object" - ? consoleInline(span, theme) - : span; - }); - return spans.every( - (span): span is ConsoleText => - span.type === "text" && !span.text.includes("\n"), - ) - ? createTableCell(spans) - : createTableCell(consoleInline(value, theme)); + const spans = findOptimalExpansion(value, theme, maxCellLength); + return spans === undefined + ? createTableCell(inspectInline(value, theme)) + : createTableCell(spans); +} + +function findOptimalExpansion( + value: unknown, + theme: "light" | "dark", + maxCellLength: number, +): ConsoleText[] | undefined { + let optimal: ConsoleText[] | undefined; + let depth = 1; + while (true) { + let hasObject = false; + const spans = inspectAny( + value, + { + theme, + wrap: "single-line", + print: false, + line: false, + indent: 0, + depth: depth + 1, + }, + { + depth: depth, + indent: 0, + wrap: Number.MAX_SAFE_INTEGER, + }, + ).map((span) => { + return typeof span === "string" + ? consoleText(span) + : span.type === "object" + ? ((hasObject = true), inspectInline(span, theme)) + : span; + }); + if ( + spans.every((span): span is ConsoleText => span.type === "text") && + spansLength(spans) <= maxCellLength + ) { + depth += 1; + optimal = spans; + if (!hasObject) { + break; + } + if (depth > 6) { + break; + } + } else { + break; + } + } + return optimal; } diff --git a/src/extras/consoleTable/flatObjectOrArrayTable.ts b/src/extras/consoleTable/flatObjectOrArrayTable.ts index 06991a0..e44803c 100644 --- a/src/extras/consoleTable/flatObjectOrArrayTable.ts +++ b/src/extras/consoleTable/flatObjectOrArrayTable.ts @@ -14,7 +14,7 @@ export default function flatObjectOrArrayTable( const spans: ConsoleText[] = []; const isArray = Array.isArray(object); const keys = Object.keys(object); - const lengthPerColumn = Math.floor(options.lineLength / keys.length); + const lengthPerColumn = Math.floor(options.lineLength / 2); const rows = keys.map((key) => { return [ createTableCell( diff --git a/src/inspect/consoleInspect.ts b/src/inspect/consoleInspect.ts index 5b55aeb..be7867e 100644 --- a/src/inspect/consoleInspect.ts +++ b/src/inspect/consoleInspect.ts @@ -2,15 +2,15 @@ import consolePrint from "../core/consolePrint"; import inspectAny from "./inspectors/inspectAny"; import consoleApply from "../core/consoleApply"; import ConsoleSpan from "../core/ConsoleSpan"; -import defaultLineLength from "../utils/defaultLineLength"; +import guessAvailableLength from "../utils/guessAvailableLength"; export interface ConsoleInspectOptions { line?: boolean; indent?: number; print?: boolean; depth?: number; - lineLength?: number; theme?: "light" | "dark"; + wrap?: "auto" | "single-line" | "multi-line" | 100; // preferMultiLine?: boolean; // preferSingleLine?: boolean; // preferTables?: boolean; @@ -19,31 +19,37 @@ export interface ConsoleInspectOptions { export interface ConsoleInspectContext { indent: number; depth: number; + wrap: number; } export default function consoleInspect( value: unknown, options?: ConsoleInspectOptions, ): ConsoleSpan[] { + const requiredOptions: Required = { + depth: 2, + indent: 4, + line: false, + wrap: "auto", + theme: matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light", + print: true, + ...options, + }; const spans = consoleApply( - inspectAny( - value, - { - depth: 2, - indent: 4, - line: false, - lineLength: defaultLineLength(), - theme: matchMedia("(prefers-color-scheme: dark)").matches - ? "dark" - : "light", - print: true, - ...options, - }, - { - depth: 0, - indent: 0, - }, - ), + inspectAny(value, requiredOptions, { + depth: 0, + indent: 0, + wrap: + requiredOptions.wrap === "auto" + ? guessAvailableLength() + : requiredOptions.wrap === "single-line" + ? Number.MAX_SAFE_INTEGER + : requiredOptions.wrap === "multi-line" + ? 0 + : requiredOptions.wrap, + }), { lineHeight: "1.6", }, diff --git a/src/inspect/inspectors/inspectAny.ts b/src/inspect/inspectors/inspectAny.ts index 5f6ab69..41721d5 100644 --- a/src/inspect/inspectors/inspectAny.ts +++ b/src/inspect/inspectors/inspectAny.ts @@ -3,16 +3,15 @@ import inspectObject from "./inspectObject"; import isIterable from "../../utils/isIterable"; import isPrimitive from "../../utils/isPrimitive"; import inspectPrimitive from "./inspectPrimitive"; -import { consoleText } from "../../core/consoleText"; -import ConsoleSpan from "../../core/ConsoleSpan"; -import { consoleObject } from "../../core/consoleObject"; +import { ConsoleText, consoleText } from "../../core/consoleText"; +import { ConsoleObject, consoleObject } from "../../core/consoleObject"; import { ConsoleInspectContext, ConsoleInspectOptions } from "../consoleInspect"; export default function inspectAny( value: unknown, options: Required, context: ConsoleInspectContext, -): ConsoleSpan[] { +): (ConsoleText | ConsoleObject)[] { if (isPrimitive(value)) { return [inspectPrimitive(value, options.theme)]; } else if (Array.isArray(value) || isIterable(value)) { diff --git a/src/inspect/inspectors/inspectArray.ts b/src/inspect/inspectors/inspectArray.ts index 4105b6b..b1be103 100644 --- a/src/inspect/inspectors/inspectArray.ts +++ b/src/inspect/inspectors/inspectArray.ts @@ -1,7 +1,5 @@ import { Primitive } from "type-fest"; import { ConsoleText, consoleText } from "../../core/consoleText"; -import inspectPrimitive from "./inspectPrimitive"; -import ConsoleSpan from "../../core/ConsoleSpan"; import isPrimitive from "../../utils/isPrimitive"; import inspectAny from "./inspectAny"; import consoleStyles from "../utils/consoleStyles"; @@ -10,29 +8,29 @@ import { ConsoleInspectOptions, } from "../consoleInspect"; import hasOnlyPrimitives from "../../utils/hasOnlyPrimitives"; -import { consoleObject } from "../../core/consoleObject"; +import { ConsoleObject, consoleObject } from "../../core/consoleObject"; import createIndent from "../utils/createIndent"; import spansLength from "../../utils/spansLength"; -import { consoleGroup } from "../../core/consoleGroup"; +import inspectInline from "./inspectInline"; export default function inspectArray( array: unknown[], options: Required, context: ConsoleInspectContext, -): ConsoleSpan[] { - if (array.every(isPrimitive)) { +): (ConsoleText | ConsoleObject)[] { + if (options.wrap !== "auto" || array.every(isPrimitive)) { const singleLine = singleLineArray(array as Primitive[], options); - if (spansLength(singleLine) + context.indent <= options.lineLength) { + if (spansLength(singleLine) + context.indent <= context.wrap) { // special case: top-level array // we otherwise can't use groups because they call `consoleFlush()` - if (context.depth === 0) { - return [ - consoleGroup({ - header: singleLine, - body: multiLineArray(array, options, context), - }), - ]; - } + // if (context.depth === 0) { + // return [ + // consoleGroup({ + // header: singleLine, + // body: multiLineArray(array, options, context), + // }), + // ]; + // } return singleLine; } } @@ -47,13 +45,13 @@ export default function inspectArray( function singleLineArray( array: Primitive[], options: Required, -): ConsoleText[] { +): (ConsoleText | ConsoleObject)[] { return [ consoleText("["), ...array.flatMap((value, i) => { return i === 0 - ? [inspectPrimitive(value, options.theme)] - : [consoleText(", "), inspectPrimitive(value, options.theme)]; + ? [inspectInline(value, options.theme)] + : [consoleText(", "), inspectInline(value, options.theme)]; }), consoleText("]"), consoleText(` (${array.length})`, consoleStyles[options.theme].dimmed), @@ -64,7 +62,7 @@ function multiLineArray( array: unknown[], options: Required, context: ConsoleInspectContext, -): ConsoleSpan[] { +): (ConsoleText | ConsoleObject)[] { return array.flatMap((value, i) => { const indexText = `[${i}]: `; const valueSpans = @@ -73,11 +71,13 @@ function multiLineArray( context.depth + 1 >= options.depth ? inspectAny(value, options, { indent: 0, + wrap: context.wrap, depth: context.depth + 1, }) : [ consoleText("\n"), ...inspectAny(value, options, { + wrap: context.wrap, indent: context.indent + options.indent, depth: context.depth + 1, }), diff --git a/src/utils/consoleInline.ts b/src/inspect/inspectors/inspectInline.ts similarity index 57% rename from src/utils/consoleInline.ts rename to src/inspect/inspectors/inspectInline.ts index ab916db..223cfd6 100644 --- a/src/utils/consoleInline.ts +++ b/src/inspect/inspectors/inspectInline.ts @@ -1,9 +1,9 @@ -import { consoleText, ConsoleText } from "../core/consoleText"; -import isPrimitive from "./isPrimitive"; -import inspectPrimitive from "../inspect/inspectors/inspectPrimitive"; -import isIterable from "./isIterable"; +import { consoleText, ConsoleText } from "../../core/consoleText"; +import isPrimitive from "../../utils/isPrimitive"; +import inspectPrimitive from "./inspectPrimitive"; +import isIterable from "../../utils/isIterable"; -export default function consoleInline( +export default function inspectInline( value: unknown, theme: "light" | "dark", ): ConsoleText { diff --git a/src/inspect/inspectors/inspectObject.ts b/src/inspect/inspectors/inspectObject.ts index 51d6d28..a773800 100644 --- a/src/inspect/inspectors/inspectObject.ts +++ b/src/inspect/inspectors/inspectObject.ts @@ -1,4 +1,3 @@ -import ConsoleSpan from "../../core/ConsoleSpan"; import { ConsoleText, consoleText } from "../../core/consoleText"; import consoleStyles from "../utils/consoleStyles"; import inspectAny from "./inspectAny"; @@ -8,9 +7,8 @@ import { ConsoleInspectOptions, } from "../consoleInspect"; import { Primitive } from "type-fest"; -import inspectPrimitive from "./inspectPrimitive"; import hasOnlyPrimitives from "../../utils/hasOnlyPrimitives"; -import { consoleObject } from "../../core/consoleObject"; +import { ConsoleObject, consoleObject } from "../../core/consoleObject"; import createIndent from "../utils/createIndent"; import spansLength from "../../utils/spansLength"; import isPlainObject from "is-plain-obj"; @@ -19,17 +17,18 @@ export default function inspectObject( object: object, options: Required, context: ConsoleInspectContext, -): ConsoleSpan[] { +): (ConsoleText | ConsoleObject)[] { if (!isPlainObject(object)) { return [consoleObject(object)]; } - if (hasOnlyPrimitives(object)) { + if (options.wrap !== "auto" || hasOnlyPrimitives(object)) { const singleLine = singleLineObject( object as Record, options, + context, ); - if (spansLength(singleLine) + context.indent <= options.lineLength) { + if (spansLength(singleLine) + context.indent <= context.wrap) { return singleLine; } } @@ -44,8 +43,9 @@ export default function inspectObject( function singleLineObject( value: Record, options: Required, -): ConsoleText[] { - const spans: ConsoleText[] = [consoleText("{ ")]; + context: ConsoleInspectContext, +): (ConsoleText | ConsoleObject)[] { + const spans: (ConsoleText | ConsoleObject)[] = [consoleText("{ ")]; let isFirst = true; for (const key in value) { @@ -56,7 +56,13 @@ function singleLineObject( } spans.push(consoleText(key, consoleStyles[options.theme].dimmed)); spans.push(consoleText(": ")); - spans.push(inspectPrimitive(value[key], options.theme)); + spans.push( + ...inspectAny(value[key], options, { + ...context, + indent: 0, + depth: context.depth + 1, + }), + ); } spans.push(consoleText(" }")); @@ -68,8 +74,8 @@ function multiLineObject( object: object, options: Required, context: ConsoleInspectContext, -): ConsoleSpan[] { - const spans: ConsoleSpan[] = []; +): (ConsoleText | ConsoleObject)[] { + const spans: (ConsoleText | ConsoleObject)[] = []; const sortedKeys = sortKeys(object); const maxLength = maxKeyLength(object); @@ -92,6 +98,7 @@ function multiLineObject( ) { spans.push( ...inspectAny(value, options, { + wrap: context.wrap, indent: context.indent, depth: context.depth + 1, }), @@ -100,6 +107,7 @@ function multiLineObject( spans.push(consoleText("\n")); spans.push( ...inspectAny(value, options, { + wrap: context.wrap, indent: context.indent + options.indent, depth: context.depth + 1, }), diff --git a/src/utils/defaultLineLength.ts b/src/utils/guessAvailableLength.ts similarity index 90% rename from src/utils/defaultLineLength.ts rename to src/utils/guessAvailableLength.ts index 02f271b..bea4d0f 100644 --- a/src/utils/defaultLineLength.ts +++ b/src/utils/guessAvailableLength.ts @@ -1,4 +1,4 @@ -export default function defaultLineLength(): number { +export default function guessAvailableLength(): number { // - if a window is 1400px wide, a DevTools window positioned horizontally // will have around 1150 space for printing characters on one line. note // that this is variable due to the right side being taken by the name of diff --git a/src/utils/spansLength.ts b/src/utils/spansLength.ts index 70d1e4e..6e0787f 100644 --- a/src/utils/spansLength.ts +++ b/src/utils/spansLength.ts @@ -1,9 +1,16 @@ import { ConsoleText } from "../core/consoleText"; +import { ConsoleObject } from "../core/consoleObject"; -export default function spansLength(spans: ConsoleText[]): number { +export default function spansLength( + spans: (ConsoleText | ConsoleObject)[], +): number { let charsCount = 0; for (const span of spans) { - charsCount += span.text.length; + if (span.type === "text") { + charsCount += span.text.length; + } else { + charsCount += Object.keys(span.object).length * 8; + } } return charsCount; }