feat(smartjson): Add JSONL stringify and ordering comparator; fix empty buffer handling; refactor Smartjson folding/enfolding

This commit is contained in:
2025-09-12 19:30:15 +00:00
parent 58322d23f4
commit fe8b5ce7c0
6 changed files with 78 additions and 30 deletions

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartjson',
version: '5.0.21',
version: '5.1.0',
description: 'A library for handling typed JSON data, providing functionalities for parsing, stringifying, and working with JSON objects, including support for encoding and decoding buffers.'
}

View File

@@ -52,11 +52,7 @@ const replacer: TParseReplacer = (key, value) => {
// Handle IBufferLike objects with a .data property
if ('data' in value && isArray(value.data)) {
if (value.data.length > 0) {
bufferData = new Uint8Array(value.data);
} else {
return ''; // Return empty string for empty data arrays
}
bufferData = new Uint8Array(value.data);
}
// Handle Uint8Array directly
else if (value instanceof Uint8Array) {

View File

@@ -22,6 +22,10 @@ export const parseJsonL = (jsonlData: string): JsonObject[] => {
return parsedData;
}
export const stringifyJsonL = (items: any[]): string => {
return items.map((item) => stringify(item)).join('\n');
}
/**
*
* @param objArg
@@ -34,7 +38,20 @@ export const stringify = (
): string => {
const bufferedJson = bufferhandling.stringify(objArg);
objArg = JSON.parse(bufferedJson);
let returnJson = plugins.stableJson(objArg, optionsArg);
// derive a simple comparator from simpleOrderArray if provided and no custom cmp supplied
let options = { ...optionsArg };
if (simpleOrderArray && !options.cmp) {
const order = new Map<string, number>();
simpleOrderArray.forEach((key, idx) => order.set(key, idx));
options.cmp = (a, b) => {
const aIdx = order.has(a.key) ? (order.get(a.key) as number) : Number.POSITIVE_INFINITY;
const bIdx = order.has(b.key) ? (order.get(b.key) as number) : Number.POSITIVE_INFINITY;
if (aIdx !== bIdx) return aIdx - bIdx;
// fallback to lexicographic order for stable behavior
return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
};
}
let returnJson = plugins.stableJson(objArg, options);
return returnJson;
};
@@ -62,9 +79,10 @@ export class Smartjson {
*/
public static enfoldFromObject<T extends typeof Smartjson>(this: T, objectArg: any): InstanceType<T> {
const newInstance = new this() as InstanceType<T>;
const saveables: string[] = (newInstance as any).saveableProperties || [];
for (const keyName in objectArg) {
if (newInstance.saveableProperties.indexOf(keyName) !== -1) {
newInstance[keyName] = objectArg[keyName];
if (saveables.indexOf(keyName) !== -1) {
(newInstance as any)[keyName] = objectArg[keyName];
}
}
return newInstance;
@@ -88,26 +106,9 @@ export class Smartjson {
* folds a class into an object
*/
public foldToObject() {
const newFoldedObject: { [key: string]: any } = {};
const trackSet = new Set<Smartjson>();
const foldValue = (val: any): any => {
if (val instanceof Smartjson) {
if (trackSet.has(val)) {
throw new Error('cycle detected');
}
trackSet.add(val);
return val.foldToObjectInternal(trackSet);
}
if (Array.isArray(val)) {
return val.map((item) => foldValue(item));
}
return plugins.lodashCloneDeep(val);
};
for (const keyName of this.saveableProperties) {
const value = this[keyName];
newFoldedObject[keyName] = foldValue(value);
}
return newFoldedObject;
trackSet.add(this);
return this.foldToObjectInternal(trackSet);
}
private foldToObjectInternal(trackSet: Set<Smartjson>) {
@@ -125,7 +126,8 @@ export class Smartjson {
}
return plugins.lodashCloneDeep(val);
};
for (const keyName of this.saveableProperties) {
const props: string[] = (this as any).saveableProperties || [];
for (const keyName of props) {
const value = this[keyName];
result[keyName] = foldValue(value);
}