@ -1,4 +1,9 @@
import type { BuildVisibleJsonRowsOptions , JsonViewNode , JsonViewNodeType } from "./types" ;
import type { BuildVisibleJsonRowsOptions , JsonViewNode , JsonViewNodeType } from "./types" ;
import {
formatCircularReference ,
isCircularReferenceMarker ,
normalizeVueValue ,
} from "./normalizeValue" ;
type PlainObject = Record < string , unknown > ;
type PlainObject = Record < string , unknown > ;
type JsonContainerKind = "object" | "array" | "map" | "set" ;
type JsonContainerKind = "object" | "array" | "map" | "set" ;
@ -20,6 +25,22 @@ interface LineCounter {
nextLineNumber : number ;
nextLineNumber : number ;
}
}
function toDisplayPath ( path : string , rootPath : string ) {
if ( path === rootPath ) {
return "$" ;
}
if ( path . startsWith ( ` ${ rootPath } . ` ) ) {
return ` $ ${ path . slice ( rootPath . length ) } ` ;
}
if ( path . startsWith ( ` ${ rootPath } [ ` ) ) {
return ` $ ${ path . slice ( rootPath . length ) } ` ;
}
return path ;
}
function isRecordLike ( value : unknown ) : value is Record < string , unknown > {
function isRecordLike ( value : unknown ) : value is Record < string , unknown > {
return value !== null && typeof value === "object" && ! Array . isArray ( value ) && ! ( value instanceof Map ) && ! ( value instanceof Set ) ;
return value !== null && typeof value === "object" && ! Array . isArray ( value ) && ! ( value instanceof Map ) && ! ( value instanceof Set ) ;
}
}
@ -79,6 +100,13 @@ function isExpanded(path: string, level: number, length: number, options: BuildV
}
}
function formatKeyDisplay ( value : unknown ) {
function formatKeyDisplay ( value : unknown ) {
const normalizedValue = normalizeVueValue ( value ) ;
if ( isCircularReferenceMarker ( normalizedValue ) ) {
return formatCircularReference ( normalizedValue . path ) ;
}
value = normalizedValue ;
if ( typeof value === "string" ) {
if ( typeof value === "string" ) {
return JSON . stringify ( value ) ;
return JSON . stringify ( value ) ;
}
}
@ -113,6 +141,13 @@ function formatKeyDisplay(value: unknown) {
}
}
function formatPrimitiveDisplay ( value : unknown ) {
function formatPrimitiveDisplay ( value : unknown ) {
const normalizedValue = normalizeVueValue ( value ) ;
if ( isCircularReferenceMarker ( normalizedValue ) ) {
return formatCircularReference ( normalizedValue . path ) ;
}
value = normalizedValue ;
if ( typeof value === "string" ) {
if ( typeof value === "string" ) {
return JSON . stringify ( value ) ;
return JSON . stringify ( value ) ;
}
}
@ -138,6 +173,10 @@ function formatPrimitiveDisplay(value: unknown) {
}
}
function getContainerKind ( value : unknown ) : JsonContainerKind | null {
function getContainerKind ( value : unknown ) : JsonContainerKind | null {
value = normalizeVueValue ( value ) ;
if ( isCircularReferenceMarker ( value ) ) {
return null ;
}
if ( Array . isArray ( value ) ) {
if ( Array . isArray ( value ) ) {
return "array" ;
return "array" ;
}
}
@ -201,7 +240,12 @@ function getContainerNodeType(kind: JsonContainerKind, state: "start" | "end" |
return "arrayCollapsed" ;
return "arrayCollapsed" ;
}
}
function countValueLines ( value : unknown , ancestors = new WeakSet < object > ( ) ) : number {
function countValueLines ( value : unknown , ancestors = new WeakMap < object , true > ( ) ) : number {
value = normalizeVueValue ( value ) ;
if ( isCircularReferenceMarker ( value ) ) {
return 1 ;
}
const kind = getContainerKind ( value ) ;
const kind = getContainerKind ( value ) ;
if ( ! kind ) {
if ( ! kind ) {
return 1 ;
return 1 ;
@ -212,7 +256,7 @@ function countValueLines(value: unknown, ancestors = new WeakSet<object>()): num
return 1 ;
return 1 ;
}
}
ancestors . add ( reference ) ;
ancestors . set ( reference , tru e ) ;
const total =
const total =
kind === "array"
kind === "array"
@ -232,7 +276,7 @@ function countValueLines(value: unknown, ancestors = new WeakSet<object>()): num
return total ;
return total ;
}
}
function countContainerChildLines ( kind : JsonContainerKind , value : JsonContainerValue , ancestors : WeakSet < object > ) {
function countContainerChildLines ( kind : JsonContainerKind , value : JsonContainerValue , ancestors : WeakMap < object , true > ) {
if ( kind === "array" ) {
if ( kind === "array" ) {
return ( value as unknown [ ] ) . reduce < number > ( ( sum , entry ) = > sum + countValueLines ( entry , ancestors ) , 0 ) ;
return ( value as unknown [ ] ) . reduce < number > ( ( sum , entry ) = > sum + countValueLines ( entry , ancestors ) , 0 ) ;
}
}
@ -287,8 +331,24 @@ function appendValueRows(
rows : JsonViewNode [ ] ,
rows : JsonViewNode [ ] ,
options : BuildVisibleJsonRowsOptions ,
options : BuildVisibleJsonRowsOptions ,
counter : LineCounter ,
counter : LineCounter ,
ancestors : WeakSet < object >
ancestors : WeakMap < object , string >
) {
) {
const normalizedValue = normalizeVueValue ( value , toDisplayPath ( context . path , options . rootPath ) ) ;
if ( isCircularReferenceMarker ( normalizedValue ) ) {
rows . push (
createNode (
counter ,
context ,
"content" ,
formatCircularReference ( normalizedValue . path ? ? toDisplayPath ( context . path , options . rootPath ) ) ,
normalizedValue ,
{ isLeaf : true }
)
) ;
return ;
}
value = normalizedValue ;
const kind = getContainerKind ( value ) ;
const kind = getContainerKind ( value ) ;
if ( ! kind ) {
if ( ! kind ) {
rows . push ( createNode ( counter , context , "content" , formatPrimitiveDisplay ( value ) , value , { isLeaf : true } ) ) ;
rows . push ( createNode ( counter , context , "content" , formatPrimitiveDisplay ( value ) , value , { isLeaf : true } ) ) ;
@ -296,12 +356,17 @@ function appendValueRows(
}
}
const reference = value as object ;
const reference = value as object ;
if ( ancestors . has ( reference ) ) {
const existingPath = ancestors . get ( reference ) ;
rows . push ( createNode ( counter , context , "content" , "[Circular]" , value , { isLeaf : true } ) ) ;
if ( existingPath ) {
rows . push (
createNode ( counter , context , "content" , formatCircularReference ( toDisplayPath ( existingPath , options . rootPath ) ) , value , {
isLeaf : true ,
} )
) ;
return ;
return ;
}
}
ancestors . add ( reference ) ;
ancestors . set ( reference , context . path ) ;
appendContainerRows ( kind , value as JsonContainerValue , context , rows , options , counter , ancestors ) ;
appendContainerRows ( kind , value as JsonContainerValue , context , rows , options , counter , ancestors ) ;
ancestors . delete ( reference ) ;
ancestors . delete ( reference ) ;
}
}
@ -313,11 +378,11 @@ function appendContainerRows(
rows : JsonViewNode [ ] ,
rows : JsonViewNode [ ] ,
options : BuildVisibleJsonRowsOptions ,
options : BuildVisibleJsonRowsOptions ,
counter : LineCounter ,
counter : LineCounter ,
ancestors : WeakSet < object >
ancestors : WeakMap < object , string >
) {
) {
const length = getContainerLength ( value , kind ) ;
const length = getContainerLength ( value , kind ) ;
const expanded = isExpanded ( context . path , context . level , length , options ) ;
const expanded = isExpanded ( context . path , context . level , length , options ) ;
const totalLineCount = 2 + countContainerChildLines ( kind , value , anc es to rs ) ;
const totalLineCount = 2 + countContainerChildLines ( kind , value , new WeakMap < obj ect , true > ( ) ) ;
if ( ! expanded ) {
if ( ! expanded ) {
rows . push (
rows . push (
@ -398,13 +463,14 @@ function appendContainerRows(
} ) ;
} ) ;
} else {
} else {
Array . from ( value as Map < unknown , unknown > ) . forEach ( ( [ keyValue , childValue ] , index ) = > {
Array . from ( value as Map < unknown , unknown > ) . forEach ( ( [ keyValue , childValue ] , index ) = > {
const normalizedKeyValue = normalizeVueValue ( keyValue , toDisplayPath ( context . path , options . rootPath ) ) ;
appendValueRows (
appendValueRows (
childValue ,
childValue ,
{
{
path : buildMapPath ( context . path , k eyValue, index ) ,
path : buildMapPath ( context . path , normalizedK eyValue, index ) ,
level : context.level + 1 ,
level : context.level + 1 ,
displayKey : formatKeyDisplay ( k eyValue) ,
displayKey : formatKeyDisplay ( normalizedK eyValue) ,
keyValue ,
keyValue : normalizedKeyValue ,
showComma : index < length - 1 ,
showComma : index < length - 1 ,
posInSet : index + 1 ,
posInSet : index + 1 ,
setSize : length ,
setSize : length ,
@ -446,7 +512,7 @@ export function buildVisibleJsonRows(value: unknown, options: BuildVisibleJsonRo
rows ,
rows ,
options ,
options ,
counter ,
counter ,
new WeakSet < object > ( )
new WeakMap < object , string > ( )
) ;
) ;
return rows ;
return rows ;
}
}