Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
374a8e411a | |||
fe8b5ce7c0 | |||
58322d23f4 | |||
2f012fc0ad | |||
9bb6e0b497 | |||
5275e13360 | |||
03fe2174d1 | |||
7df82ce64d | |||
09b74e4053 |
217
changelog.md
Normal file
217
changelog.md
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-09-12 - 5.1.0 - feat(smartjson)
|
||||||
|
Add JSONL stringify and ordering comparator; fix empty buffer handling; refactor Smartjson folding/enfolding
|
||||||
|
|
||||||
|
- Export stringifyJsonL(items: any[]) and add README documentation for JSONL stringification
|
||||||
|
- stringify(obj, simpleOrderArray) now derives a stable-json comparator from simpleOrderArray when no custom cmp is provided, ensuring predictable key ordering
|
||||||
|
- Fix buffer handling: empty Uint8Array values are preserved (no longer serialized to an empty string) and encoding/decoding logic improved
|
||||||
|
- Refactor Smartjson.enfoldFromObject to safely use saveableProperties and avoid repeated property access
|
||||||
|
- Simplify Smartjson.foldToObject to delegate to an internal foldToObjectInternal with cycle detection and correct nested instance handling
|
||||||
|
- Add unit tests for empty buffers, JSONL parse/stringify, deepEqualJsonLStrings, and simpleOrderArray comparator behavior
|
||||||
|
|
||||||
|
## 2025-09-12 - 5.0.21 - fix(Smartjson)
|
||||||
|
Cross-platform buffer/base64 handling, safer folding with cycle detection, parsing fixes, docs and dependency updates
|
||||||
|
|
||||||
|
- bufferhandling: prefer Node Buffer for base64 encode/decode when available and fall back to browser APIs for cross-platform support
|
||||||
|
- parseJsonL: more robust parsing of JSON Lines (trim lines and use smartjson.parse to restore buffers/typed arrays)
|
||||||
|
- parseBase64: use smartstring.base64.decodeUri or decode fallback before parsing, then parse result via smartjson.parse
|
||||||
|
- Smartjson class: add TypeScript generics to enfold methods, introduce foldToObjectInternal and robust cycle detection using Set, properly handle arrays and deep-clone values
|
||||||
|
- Tests: updated tap import path to @git.zone/tstest/tapbundle
|
||||||
|
- package.json: bumped several devDependencies and dependency versions and added packageManager pin
|
||||||
|
- Documentation: expanded README with examples, API reference and usage guidance
|
||||||
|
- Repo config: added pnpm-workspace.yaml and .claude/settings.local.json
|
||||||
|
|
||||||
|
## 2024-05-29 - 5.0.20 - docs
|
||||||
|
Update package description.
|
||||||
|
|
||||||
|
- Update package description text.
|
||||||
|
|
||||||
|
## 2024-05-27 - 5.0.19 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-04-17 - 5.0.18 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-04-17 - 5.0.17 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-04-17 - 5.0.16 - build/core
|
||||||
|
Build/config updates and core fixes.
|
||||||
|
|
||||||
|
- Updated tsconfig configuration (2024-04-14).
|
||||||
|
- Updated npmextra.json githost entries (multiple updates in early April).
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-03-19 - 5.0.15 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-03-19 - 5.0.14 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-03-03 - 5.0.13 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-03-03 - 5.0.12 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-03-03 - 5.0.11 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2024-02-25 - 5.0.10 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2023-08-24 - 5.0.9 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2023-08-19 - 5.0.8 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2023-08-19 - 5.0.7 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2023-07-10 - 5.0.6 - infra/core
|
||||||
|
Organization and core updates.
|
||||||
|
|
||||||
|
- Switched to new organization scheme.
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2023-06-03 - 5.0.5 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-10-26 - 5.0.4 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-10-26 - 5.0.3 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-10-26 - 5.0.2 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-09-13 - 5.0.1 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-06-26 - 5.0.0 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2022-06-09 - 4.0.7 - core (BREAKING CHANGE)
|
||||||
|
Breaking change in core.
|
||||||
|
|
||||||
|
- BREAKING CHANGE: core-related update (see code/compat notes).
|
||||||
|
- Miscellaneous core updates.
|
||||||
|
|
||||||
|
## 2022-06-09 - 4.0.6 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 4.0.4 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 4.0.3 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 4.0.2 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 4.0.1 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 4.0.0 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-05 - 3.0.12 - core (BREAKING CHANGE)
|
||||||
|
Breaking change in core.
|
||||||
|
|
||||||
|
- BREAKING CHANGE: core-related update (see migration notes).
|
||||||
|
- Miscellaneous core updates.
|
||||||
|
|
||||||
|
## 2020-10-03 - 3.0.11 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2020-10-03 - 3.0.10 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2019-02-14 - 3.0.0 - security
|
||||||
|
Security-related update.
|
||||||
|
|
||||||
|
- Added snyk policy for security scanning.
|
||||||
|
|
||||||
|
## 2019-02-14 - 2.0.2 - core (BREAKING CHANGE)
|
||||||
|
Breaking change in core API.
|
||||||
|
|
||||||
|
- BREAKING CHANGE: renamed Folable to Smartjson and added deterministic stringify.
|
||||||
|
- Update consumers accordingly.
|
||||||
|
|
||||||
|
## 2018-09-05 - 2.0.1 - core
|
||||||
|
Core fixes.
|
||||||
|
|
||||||
|
- Miscellaneous core updates and fixes.
|
||||||
|
|
||||||
|
## 2018-07-23 - 1.0.1 - scope (BREAKING CHANGE)
|
||||||
|
Scope change.
|
||||||
|
|
||||||
|
- BREAKING CHANGE: changed package scope.
|
||||||
|
- See migration notes for scope changes.
|
||||||
|
|
||||||
|
## 2017-02-27 - 1.0.0 - docs/init
|
||||||
|
Initial release.
|
||||||
|
|
||||||
|
- Added README.
|
||||||
|
- Initial project files and setup.
|
||||||
|
|
||||||
|
## 2018-07-23 — 2019-12-15 - 2.0.0, 3.0.1, 3.0.9 - version-only releases
|
||||||
|
Version-only tags / non-descriptive releases.
|
||||||
|
|
||||||
|
- These releases are recorded as version bumps without additional changelog details.
|
||||||
|
- Affected tags: 2.0.0, 3.0.1, 3.0.9.
|
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartjson",
|
"name": "@push.rocks/smartjson",
|
||||||
"version": "5.0.18",
|
"version": "5.1.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"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.",
|
"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.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@@ -12,24 +12,23 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+ssh://git@gitlab.com/pushrocks/smartjson.git"
|
"url": "https://code.foss.global/push.rocks/smartjson.git"
|
||||||
},
|
},
|
||||||
"author": "Lossless GmbH",
|
"author": "Lossless GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://gitlab.com/pushrocks/smartjson/issues"
|
"url": "https://gitlab.com/pushrocks/smartjson/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/pushrocks/smartjson#README",
|
"homepage": "https://code.foss.global/push.rocks/smartjson",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsbuild": "^2.1.66",
|
"@git.zone/tsbuild": "^2.6.8",
|
||||||
"@git.zone/tsrun": "^1.2.44",
|
"@git.zone/tsrun": "^1.3.3",
|
||||||
"@git.zone/tstest": "^1.0.88",
|
"@git.zone/tstest": "^2.3.8",
|
||||||
"@push.rocks/tapbundle": "^5.0.23",
|
"@types/node": "^22"
|
||||||
"@types/node": "^20.12.7"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@push.rocks/smartenv": "^5.0.12",
|
"@push.rocks/smartenv": "^5.0.13",
|
||||||
"@push.rocks/smartstring": "^4.0.15",
|
"@push.rocks/smartstring": "^4.1.0",
|
||||||
"fast-json-stable-stringify": "^2.1.0",
|
"fast-json-stable-stringify": "^2.1.0",
|
||||||
"lodash.clonedeep": "^4.5.0"
|
"lodash.clonedeep": "^4.5.0"
|
||||||
},
|
},
|
||||||
@@ -61,5 +60,6 @@
|
|||||||
"TypeScript support",
|
"TypeScript support",
|
||||||
"data encoding",
|
"data encoding",
|
||||||
"data decoding"
|
"data decoding"
|
||||||
]
|
],
|
||||||
|
"packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748"
|
||||||
}
|
}
|
||||||
|
10993
pnpm-lock.yaml
generated
10993
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
- puppeteer
|
367
readme.md
367
readme.md
@@ -1,125 +1,360 @@
|
|||||||
# @push.rocks/smartjson
|
# @push.rocks/smartjson
|
||||||
typed json handlers
|
**🚀 Typed JSON handling for modern Node.js and TypeScript applications**
|
||||||
|
|
||||||
## Install
|
A powerful library for working with JSON in TypeScript, providing type-safe serialization, advanced buffer handling, deep object comparison, and support for complex class instances. Perfect for applications that need reliable JSON manipulation with full TypeScript support.
|
||||||
|
|
||||||
To install `@push.rocks/smartjson`, you can use npm or yarn as follows:
|
## Installation
|
||||||
|
|
||||||
```shell
|
```bash
|
||||||
|
# Using npm
|
||||||
npm install @push.rocks/smartjson --save
|
npm install @push.rocks/smartjson --save
|
||||||
# or using yarn
|
|
||||||
|
# Using yarn
|
||||||
yarn add @push.rocks/smartjson
|
yarn add @push.rocks/smartjson
|
||||||
|
|
||||||
|
# Using pnpm (recommended)
|
||||||
|
pnpm add @push.rocks/smartjson
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Features
|
||||||
|
|
||||||
`@push.rocks/smartjson` offers typed JSON handling, including features like folding and enfolding classes from JSON, JSON parsing with support for buffers, and comparison of JSON objects for equality. This guide will walk through various use cases and scenarios to effectively utilize `@push.rocks/smartjson` in your projects.
|
✨ **Type-Safe JSON Operations** - Full TypeScript support with proper typing
|
||||||
|
🎯 **Class Instance Serialization** - Fold and unfold class instances to/from JSON
|
||||||
|
🔐 **Buffer & Binary Support** - Seamless handling of Buffers and Typed Arrays
|
||||||
|
📊 **JSON Lines Support** - Parse and compare JSONL data streams
|
||||||
|
🎨 **Pretty Printing** - Beautiful formatted JSON output
|
||||||
|
⚡ **Stable Stringification** - Consistent key ordering for reliable comparisons
|
||||||
|
🔍 **Deep Equality Checks** - Compare complex objects and JSON structures
|
||||||
|
🌐 **Base64 Encoding** - Built-in base64 JSON encoding/decoding
|
||||||
|
|
||||||
### Basic Import
|
## Quick Start
|
||||||
|
|
||||||
First, make sure to import the module:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import * as smartjson from '@push.rocks/smartjson';
|
import * as smartjson from '@push.rocks/smartjson';
|
||||||
|
|
||||||
|
// Parse JSON with automatic buffer handling
|
||||||
|
const parsed = smartjson.parse('{"name":"example","data":{"type":"Buffer","data":[1,2,3]}}');
|
||||||
|
|
||||||
|
// Stringify with stable key ordering
|
||||||
|
const json = smartjson.stringify({ z: 1, a: 2, m: 3 });
|
||||||
|
// Result: '{"a":2,"m":3,"z":1}'
|
||||||
|
|
||||||
|
// Pretty print for human readability
|
||||||
|
const pretty = smartjson.stringifyPretty({ hello: 'world', count: 42 });
|
||||||
|
// Result:
|
||||||
|
// {
|
||||||
|
// "hello": "world",
|
||||||
|
// "count": 42
|
||||||
|
// }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Parsing and Stringifying JSON
|
## Core Functions
|
||||||
|
|
||||||
- **Parsing JSON Strings:**
|
### JSON Parsing and Stringification
|
||||||
|
|
||||||
`smartjson` enhances JSON parsing by supporting JavaScript's typed arrays, particularly with `Buffer` handling.
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const jsonString = '{"type":"Buffer","data":[116,101,115,116]}';
|
// Standard parsing with automatic Buffer detection
|
||||||
const parsedObject = smartjson.parse(jsonString);
|
const obj = smartjson.parse('{"hello":"world"}');
|
||||||
console.log(parsedObject); // Output will be based on the content of jsonString
|
|
||||||
|
// Stable stringification (consistent key ordering)
|
||||||
|
const jsonStr = smartjson.stringify({ name: 'test', id: 1 });
|
||||||
|
|
||||||
|
// Pretty printing for debugging
|
||||||
|
const prettyJson = smartjson.stringifyPretty({
|
||||||
|
nested: {
|
||||||
|
data: 'value'
|
||||||
|
}
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Stringifying Objects:**
|
### Base64 JSON Encoding
|
||||||
|
|
||||||
`@push.rocks/smartjson` provides a `stringify` function that can convert JavaScript objects into JSON strings, with special handling for `Buffer` objects.
|
Encode JSON data as base64 for safe transmission:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const myObject = {
|
const myData = {
|
||||||
exampleBuffer: new Uint8Array([116, 101, 115, 116])
|
message: 'Hello World',
|
||||||
|
timestamp: Date.now()
|
||||||
};
|
};
|
||||||
const jsonString = smartjson.stringify(myObject);
|
|
||||||
console.log(jsonString); // Will include `exampleBuffer` encoded in a special format
|
// Encode to base64
|
||||||
|
const encoded = smartjson.stringifyBase64(myData);
|
||||||
|
console.log(encoded); // Base64 string
|
||||||
|
|
||||||
|
// Decode back to object
|
||||||
|
const decoded = smartjson.parseBase64(encoded);
|
||||||
|
console.log(decoded); // Original object
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working with Base64 Encoded JSON
|
### JSON Lines (JSONL) Support
|
||||||
|
|
||||||
For cases where JSON strings are encoded in base64 format, `smartjson` offers methods to encode and decode these strings transparently.
|
Perfect for streaming data and log processing:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const objectToEncode = { hello: 'world' };
|
// Parse JSON Lines format
|
||||||
const base64EncodedJson = smartjson.stringifyBase64(objectToEncode);
|
const jsonLines = `{"event":"start","time":1234}
|
||||||
console.log(base64EncodedJson); // Encoded JSON string
|
{"event":"data","value":42}
|
||||||
|
{"event":"end","time":5678}`;
|
||||||
|
|
||||||
const decodedObject = smartjson.parseBase64(base64EncodedJson);
|
const events = smartjson.parseJsonL(jsonLines);
|
||||||
console.log(decodedObject); // Original object
|
// Result: Array of parsed objects
|
||||||
|
|
||||||
|
// Produce JSONL from objects
|
||||||
|
const jsonlOut = smartjson.stringifyJsonL([
|
||||||
|
{ event: 'start', time: 1234 },
|
||||||
|
{ event: 'data', value: 42 },
|
||||||
|
{ event: 'end', time: 5678 }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Compare JSON Lines data
|
||||||
|
const jsonL1 = `{"id":1}\n{"id":2}`;
|
||||||
|
const jsonL2 = `{"id":1}\n{"id":2}`;
|
||||||
|
const isEqual = smartjson.deepEqualJsonLStrings(jsonL1, jsonL2); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Folding and Enfolding Classes
|
## Advanced Class Serialization
|
||||||
|
|
||||||
`@push.rocks/smartjson` allows you to fold (serialize) and enfold (deserialize) class instances to and from JSON. This is particularly useful when working with typed objects and you need to maintain type integrity across serialization.
|
### Creating Serializable Classes
|
||||||
|
|
||||||
- **Defining a Foldable Class:**
|
Transform class instances to JSON and back while preserving type safety:
|
||||||
|
|
||||||
Decorate properties that should be included in JSON with `@smartjson.foldDec()`.
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Smartjson, foldDec } from '@push.rocks/smartjson';
|
import { Smartjson, foldDec } from '@push.rocks/smartjson';
|
||||||
|
|
||||||
class MyDataModel extends Smartjson {
|
class User extends Smartjson {
|
||||||
@foldDec() public someProperty: string = 'default';
|
@foldDec() public username: string;
|
||||||
|
@foldDec() public email: string;
|
||||||
|
@foldDec() public settings: UserSettings;
|
||||||
|
|
||||||
constructor(public id: number, someProperty?: string) {
|
// Properties without @foldDec won't be serialized
|
||||||
|
private internalId: string;
|
||||||
|
|
||||||
|
constructor(username: string, email: string) {
|
||||||
super();
|
super();
|
||||||
if (someProperty) this.someProperty = someProperty;
|
this.username = username;
|
||||||
|
this.email = email;
|
||||||
|
this.settings = new UserSettings();
|
||||||
|
this.internalId = Math.random().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserSettings extends Smartjson {
|
||||||
|
@foldDec() public theme: 'light' | 'dark' = 'light';
|
||||||
|
@foldDec() public notifications: boolean = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and serialize
|
||||||
|
const user = new User('john_doe', 'john@example.com');
|
||||||
|
user.settings.theme = 'dark';
|
||||||
|
|
||||||
|
// Convert to JSON
|
||||||
|
const jsonString = user.foldToJson();
|
||||||
|
console.log(jsonString);
|
||||||
|
// {"username":"john_doe","email":"john@example.com","settings":{"theme":"dark","notifications":true}}
|
||||||
|
|
||||||
|
// Restore from JSON with correct typing
|
||||||
|
const restoredUser = User.enfoldFromJson(jsonString);
|
||||||
|
console.log(restoredUser instanceof User); // true
|
||||||
|
console.log(restoredUser.settings instanceof UserSettings); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with Nested Objects
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class Company extends Smartjson {
|
||||||
|
@foldDec() public name: string;
|
||||||
|
@foldDec() public employees: Employee[] = [];
|
||||||
|
|
||||||
|
addEmployee(employee: Employee) {
|
||||||
|
this.employees.push(employee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Employee extends Smartjson {
|
||||||
|
@foldDec() public name: string;
|
||||||
|
@foldDec() public role: string;
|
||||||
|
@foldDec() public salary: number;
|
||||||
|
|
||||||
|
constructor(name: string, role: string, salary: number) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
this.role = role;
|
||||||
|
this.salary = salary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const company = new Company();
|
||||||
|
company.name = 'TechCorp';
|
||||||
|
company.addEmployee(new Employee('Alice', 'Developer', 100000));
|
||||||
|
company.addEmployee(new Employee('Bob', 'Designer', 90000));
|
||||||
|
|
||||||
|
// Serialize entire object graph
|
||||||
|
const json = company.foldToJson();
|
||||||
|
|
||||||
|
// Deserialize with all nested objects properly instantiated
|
||||||
|
const restored = Company.enfoldFromJson(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Buffer and Binary Data Handling
|
||||||
|
|
||||||
|
SmartJson seamlessly handles binary data in JSON:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Automatic Buffer handling
|
||||||
|
const dataWithBuffer = {
|
||||||
|
name: 'BinaryData',
|
||||||
|
buffer: Buffer.from('Hello World'),
|
||||||
|
typedArray: new Uint8Array([1, 2, 3, 4, 5])
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stringify (buffers are automatically encoded)
|
||||||
|
const jsonStr = smartjson.stringify(dataWithBuffer);
|
||||||
|
|
||||||
|
// Parse (buffers are automatically restored)
|
||||||
|
const restored = smartjson.parse(jsonStr);
|
||||||
|
console.log(restored.buffer); // Buffer
|
||||||
|
console.log(restored.typedArray); // Uint8Array
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deep Comparison
|
||||||
|
|
||||||
|
Compare complex objects with automatic normalization:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Deep object comparison
|
||||||
|
const obj1 = {
|
||||||
|
nested: {
|
||||||
|
array: [1, 2, { deep: 'value' }],
|
||||||
|
flag: true
|
||||||
|
},
|
||||||
|
name: 'test'
|
||||||
|
};
|
||||||
|
|
||||||
|
const obj2 = {
|
||||||
|
name: 'test', // Different order
|
||||||
|
nested: {
|
||||||
|
flag: true, // Different order
|
||||||
|
array: [1, 2, { deep: 'value' }]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEqual = smartjson.deepEqualObjects(obj1, obj2); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real-World Examples
|
||||||
|
|
||||||
|
### API Response Caching
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class CachedAPIResponse extends Smartjson {
|
||||||
|
@foldDec() public data: any;
|
||||||
|
@foldDec() public timestamp: number;
|
||||||
|
@foldDec() public endpoint: string;
|
||||||
|
|
||||||
|
isExpired(maxAge: number = 3600000): boolean {
|
||||||
|
return Date.now() - this.timestamp > maxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromAPICall(endpoint: string, data: any): CachedAPIResponse {
|
||||||
|
const response = new CachedAPIResponse();
|
||||||
|
response.endpoint = endpoint;
|
||||||
|
response.data = data;
|
||||||
|
response.timestamp = Date.now();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store API response
|
||||||
|
const apiData = await fetch('/api/users');
|
||||||
|
const cached = CachedAPIResponse.fromAPICall('/api/users', await apiData.json());
|
||||||
|
localStorage.setItem('cached_users', cached.foldToJson());
|
||||||
|
|
||||||
|
// Retrieve and check
|
||||||
|
const stored = localStorage.getItem('cached_users');
|
||||||
|
if (stored) {
|
||||||
|
const cached = CachedAPIResponse.enfoldFromJson(stored);
|
||||||
|
if (!cached.isExpired()) {
|
||||||
|
return cached.data; // Use cached data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Folding and Enfolding Instances:**
|
### Configuration Management
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const instance = new MyDataModel(1, 'value');
|
class AppConfig extends Smartjson {
|
||||||
const folded = instance.foldToJson(); // Serialize to JSON
|
@foldDec() public apiUrl: string;
|
||||||
console.log(folded);
|
@foldDec() public features: Map<string, boolean> = new Map();
|
||||||
|
@foldDec() public limits: {
|
||||||
|
maxUploadSize: number;
|
||||||
|
maxConcurrentRequests: number;
|
||||||
|
};
|
||||||
|
|
||||||
const enfoldedInstance = MyDataModel.enfoldFromJson(folded); // Deserialize back to instance
|
enableFeature(name: string) {
|
||||||
console.log(enfoldedInstance);
|
this.features.set(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
fs.writeFileSync('config.json', this.foldToJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
static load(): AppConfig {
|
||||||
|
const json = fs.readFileSync('config.json', 'utf-8');
|
||||||
|
return AppConfig.enfoldFromJson(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deep Comparison
|
## API Reference
|
||||||
|
|
||||||
`@push.rocks/smartjson` enables deep comparison of objects to determine if they are equivalent.
|
### Core Functions
|
||||||
|
|
||||||
|
- `parse(jsonString: string): any` - Parse JSON with automatic buffer handling
|
||||||
|
- `stringify(obj: any, simpleOrderArray?: string[], options?: Options): string` - Convert to JSON with stable ordering
|
||||||
|
- `stringifyPretty(obj: any): string` - Pretty print JSON with 2-space indentation
|
||||||
|
- `stringifyBase64(obj: any): string` - Encode JSON as base64
|
||||||
|
- `parseBase64(base64String: string): any` - Decode base64 JSON
|
||||||
|
- `parseJsonL(jsonLinesString: string): any[]` - Parse JSON Lines format
|
||||||
|
- `stringifyJsonL(items: any[]): string` - Stringify array to JSON Lines
|
||||||
|
- `deepEqualObjects(obj1: any, obj2: any): boolean` - Deep comparison of objects
|
||||||
|
- `deepEqualJsonLStrings(jsonL1: string, jsonL2: string): boolean` - Compare JSON Lines strings
|
||||||
|
|
||||||
|
### Smartjson Class
|
||||||
|
|
||||||
|
- `Smartjson.enfoldFromObject<T>(obj: any): T` - Create instance from plain object
|
||||||
|
- `Smartjson.enfoldFromJson<T>(json: string): T` - Create instance from JSON string
|
||||||
|
- `instance.foldToObject(): any` - Convert instance to plain object
|
||||||
|
- `instance.foldToJson(): string` - Convert instance to JSON string
|
||||||
|
|
||||||
|
### Decorators
|
||||||
|
|
||||||
|
- `@foldDec()` - Mark class property for serialization
|
||||||
|
|
||||||
|
## Performance Tips
|
||||||
|
|
||||||
|
1. **Use stable stringification** for consistent hashing and comparison
|
||||||
|
2. **Enable pretty printing** only for debugging (it's slower)
|
||||||
|
3. **Cache base64 encodings** when repeatedly sending the same data
|
||||||
|
4. **Use JSON Lines** for streaming large datasets
|
||||||
|
5. **Avoid circular references** in objects being serialized
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
If you're migrating from native JSON:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const obj1 = { a: 1, b: { c: 2 }};
|
// Before
|
||||||
const obj2 = { a: 1, b: { c: 2 }};
|
JSON.parse(jsonString);
|
||||||
|
JSON.stringify(object);
|
||||||
|
|
||||||
const isEqual = smartjson.deepEqualObjects(obj1, obj2);
|
// After
|
||||||
console.log(isEqual); // true
|
smartjson.parse(jsonString); // Adds buffer support
|
||||||
|
smartjson.stringify(object); // Adds stable ordering & buffer support
|
||||||
```
|
```
|
||||||
|
|
||||||
### Handling Buffers and Typed Arrays
|
## Browser Support
|
||||||
|
|
||||||
`smartjson` transparently handles JavaScript's `Buffer` and Typed Arrays during JSON serialization, making it effortless to work with binary data in JSON format.
|
This library supports modern browsers and Node.js environments. For older browsers, ensure you have appropriate polyfills for `TextEncoder` and `TextDecoder`.
|
||||||
|
|
||||||
```typescript
|
|
||||||
const buffer = new Uint8Array([1, 2, 3]);
|
|
||||||
const objWithBuffer = { key: buffer };
|
|
||||||
const serialized = smartjson.stringify(objWithBuffer);
|
|
||||||
|
|
||||||
const deserialized = smartjson.parse(serialized);
|
|
||||||
console.log(deserialized.key); // Instance of Uint8Array or Buffer
|
|
||||||
```
|
|
||||||
|
|
||||||
In addition to these features, `@push.rocks/smartjson` supports efficient base64 encoding/decoding, deep object comparison, and JSON Lines parsing, making it a versatile library for dealing with JSON in TypeScript projects.
|
|
||||||
|
|
||||||
For further information and more detailed examples, referring to the API documentation and the source code on [GitLab](https://gitlab.com/push.rocks/smartjson) can provide deeper insights into `@push.rocks/smartjson`'s capabilities.
|
|
||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@push.rocks/tapbundle';
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||||
|
|
||||||
import * as smartjson from '../ts/index.js';
|
import * as smartjson from '../ts/index.js';
|
||||||
|
|
||||||
@@ -72,4 +72,36 @@ tap.test('should work with buffers', async () => {
|
|||||||
expect(text).toEqual('hello');
|
expect(text).toEqual('hello');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tap.test('should handle empty buffers', async () => {
|
||||||
|
const someObject = { empty: new Uint8Array([]) };
|
||||||
|
const json = smartjson.stringify(someObject);
|
||||||
|
const parsed = smartjson.parse(json);
|
||||||
|
expect(parsed.empty).toBeInstanceOf(Uint8Array);
|
||||||
|
expect(parsed.empty.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should parse and stringify JSONL', async () => {
|
||||||
|
const items = [
|
||||||
|
{ id: 1, name: 'a' },
|
||||||
|
{ id: 2, name: 'b' }
|
||||||
|
];
|
||||||
|
const jsonl = smartjson.stringifyJsonL(items);
|
||||||
|
const parsed = smartjson.parseJsonL(jsonl);
|
||||||
|
expect(parsed).toEqual(items);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should deep-compare JSONL strings', async () => {
|
||||||
|
const a = '{"id":2,"name":"b"}\n{"id":1,"name":"a"}';
|
||||||
|
const b = '{"id":2,"name":"b"}\n{"id":1,"name":"a"}';
|
||||||
|
expect(smartjson.deepEqualJsonLStrings(a, b)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should respect simpleOrderArray comparator', async () => {
|
||||||
|
const obj = { c: 3, a: 1, b: 2 };
|
||||||
|
const ordered = smartjson.stringify(obj, ['b', 'a']);
|
||||||
|
// ensure keys b, a come before c
|
||||||
|
expect(ordered.indexOf('"b"')).toBeLessThan(ordered.indexOf('"a"'));
|
||||||
|
expect(ordered.indexOf('"a"')).toBeLessThan(ordered.indexOf('"c"'));
|
||||||
|
});
|
||||||
|
|
||||||
tap.start();
|
tap.start();
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* autocreated commitinfo by @pushrocks/commitinfo
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartjson',
|
name: '@push.rocks/smartjson',
|
||||||
version: '5.0.18',
|
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.'
|
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.'
|
||||||
}
|
}
|
||||||
|
@@ -16,10 +16,23 @@ type TParseReplacer = (this: any, key: string, value: any) => any;
|
|||||||
|
|
||||||
// Utility functions to handle base64 encoding/decoding in a cross-platform way
|
// Utility functions to handle base64 encoding/decoding in a cross-platform way
|
||||||
function base64Encode(data: Uint8Array): string {
|
function base64Encode(data: Uint8Array): string {
|
||||||
|
// Prefer Node's Buffer when available
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
// @ts-ignore Buffer might not exist in browser builds
|
||||||
|
return Buffer.from(data).toString('base64');
|
||||||
|
}
|
||||||
|
// Fallback for browsers
|
||||||
return btoa(String.fromCharCode(...data));
|
return btoa(String.fromCharCode(...data));
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64Decode(str: string): Uint8Array {
|
function base64Decode(str: string): Uint8Array {
|
||||||
|
// Prefer Node's Buffer when available
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
// @ts-ignore Buffer might not exist in browser builds
|
||||||
|
const buf = Buffer.from(str, 'base64');
|
||||||
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
||||||
|
}
|
||||||
|
// Fallback for browsers
|
||||||
return new Uint8Array(Array.from(atob(str)).map((char) => char.charCodeAt(0)));
|
return new Uint8Array(Array.from(atob(str)).map((char) => char.charCodeAt(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,11 +52,7 @@ const replacer: TParseReplacer = (key, value) => {
|
|||||||
|
|
||||||
// Handle IBufferLike objects with a .data property
|
// Handle IBufferLike objects with a .data property
|
||||||
if ('data' in value && isArray(value.data)) {
|
if ('data' in value && isArray(value.data)) {
|
||||||
if (value.data.length > 0) {
|
|
||||||
bufferData = new Uint8Array(value.data);
|
bufferData = new Uint8Array(value.data);
|
||||||
} else {
|
|
||||||
return ''; // Return empty string for empty data arrays
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Handle Uint8Array directly
|
// Handle Uint8Array directly
|
||||||
else if (value instanceof Uint8Array) {
|
else if (value instanceof Uint8Array) {
|
||||||
|
90
ts/index.ts
90
ts/index.ts
@@ -1,6 +1,5 @@
|
|||||||
import * as plugins from './smartjson.plugins.js';
|
import * as plugins from './smartjson.plugins.js';
|
||||||
import * as bufferhandling from './bufferhandling.js';
|
import * as bufferhandling from './bufferhandling.js';
|
||||||
import { json } from 'stream/consumers';
|
|
||||||
|
|
||||||
interface JsonObject {
|
interface JsonObject {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@@ -12,16 +11,21 @@ interface JsonObject {
|
|||||||
export const parse = bufferhandling.parse;
|
export const parse = bufferhandling.parse;
|
||||||
|
|
||||||
export const parseJsonL = (jsonlData: string): JsonObject[] => {
|
export const parseJsonL = (jsonlData: string): JsonObject[] => {
|
||||||
const lines = jsonlData.trim().split('\n');
|
const lines = jsonlData.split('\n');
|
||||||
const parsedData: JsonObject[] = lines.reduce((acc, line) => {
|
const parsedData: JsonObject[] = lines.reduce((acc, line) => {
|
||||||
if (line.trim().length > 0) {
|
const trimmed = line.trim();
|
||||||
acc.push(JSON.parse(line));
|
if (trimmed.length > 0) {
|
||||||
|
acc.push(parse(trimmed));
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}, [] as JsonObject[]);
|
}, [] as JsonObject[]);
|
||||||
return parsedData;
|
return parsedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const stringifyJsonL = (items: any[]): string => {
|
||||||
|
return items.map((item) => stringify(item)).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param objArg
|
* @param objArg
|
||||||
@@ -34,7 +38,20 @@ export const stringify = (
|
|||||||
): string => {
|
): string => {
|
||||||
const bufferedJson = bufferhandling.stringify(objArg);
|
const bufferedJson = bufferhandling.stringify(objArg);
|
||||||
objArg = JSON.parse(bufferedJson);
|
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;
|
return returnJson;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,21 +67,22 @@ export const stringifyBase64 = (...args: Parameters<typeof stringify>): string =
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const parseBase64 = (base64JsonStringArg: string) => {
|
export const parseBase64 = (base64JsonStringArg: string) => {
|
||||||
const simpleStringified = plugins.smartstring.base64.decode(base64JsonStringArg);
|
const base64 = plugins.smartstring.base64 as any;
|
||||||
|
const decodeFn: (input: string) => string = base64.decodeUri || base64.decode;
|
||||||
|
const simpleStringified = decodeFn(base64JsonStringArg);
|
||||||
return parse(simpleStringified);
|
return parse(simpleStringified);
|
||||||
};
|
};
|
||||||
|
|
||||||
parse;
|
|
||||||
|
|
||||||
export class Smartjson {
|
export class Smartjson {
|
||||||
/**
|
/**
|
||||||
* enfolds data from an object
|
* enfolds data from an object
|
||||||
*/
|
*/
|
||||||
public static enfoldFromObject(objectArg) {
|
public static enfoldFromObject<T extends typeof Smartjson>(this: T, objectArg: any): InstanceType<T> {
|
||||||
const newInstance = new this();
|
const newInstance = new this() as InstanceType<T>;
|
||||||
|
const saveables: string[] = (newInstance as any).saveableProperties || [];
|
||||||
for (const keyName in objectArg) {
|
for (const keyName in objectArg) {
|
||||||
if (newInstance.saveableProperties.indexOf(keyName) !== -1) {
|
if (saveables.indexOf(keyName) !== -1) {
|
||||||
newInstance[keyName] = objectArg[keyName];
|
(newInstance as any)[keyName] = objectArg[keyName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newInstance;
|
return newInstance;
|
||||||
@@ -73,7 +91,7 @@ export class Smartjson {
|
|||||||
/**
|
/**
|
||||||
* enfold from json
|
* enfold from json
|
||||||
*/
|
*/
|
||||||
public static enfoldFromJson(jsonArg: string) {
|
public static enfoldFromJson<T extends typeof Smartjson>(this: T, jsonArg: string): InstanceType<T> {
|
||||||
const objectFromJson = parse(jsonArg);
|
const objectFromJson = parse(jsonArg);
|
||||||
return this.enfoldFromObject(objectFromJson);
|
return this.enfoldFromObject(objectFromJson);
|
||||||
}
|
}
|
||||||
@@ -88,20 +106,32 @@ export class Smartjson {
|
|||||||
* folds a class into an object
|
* folds a class into an object
|
||||||
*/
|
*/
|
||||||
public foldToObject() {
|
public foldToObject() {
|
||||||
const newFoldedObject: { [key: string]: any } = {};
|
const trackSet = new Set<Smartjson>();
|
||||||
const trackMap = [];
|
trackSet.add(this);
|
||||||
for (const keyName of this.saveableProperties) {
|
return this.foldToObjectInternal(trackSet);
|
||||||
let value = this[keyName];
|
}
|
||||||
if (value instanceof Smartjson) {
|
|
||||||
if (trackMap.includes(value)) {
|
private foldToObjectInternal(trackSet: Set<Smartjson>) {
|
||||||
|
const result: { [key: string]: any } = {};
|
||||||
|
const foldValue = (val: any): any => {
|
||||||
|
if (val instanceof Smartjson) {
|
||||||
|
if (trackSet.has(val)) {
|
||||||
throw new Error('cycle detected');
|
throw new Error('cycle detected');
|
||||||
}
|
}
|
||||||
trackMap.push(value);
|
trackSet.add(val);
|
||||||
value = value.foldToObject();
|
return val.foldToObjectInternal(trackSet);
|
||||||
}
|
}
|
||||||
newFoldedObject[keyName] = plugins.lodashCloneDeep(value);
|
if (Array.isArray(val)) {
|
||||||
|
return val.map((item) => foldValue(item));
|
||||||
}
|
}
|
||||||
return newFoldedObject;
|
return plugins.lodashCloneDeep(val);
|
||||||
|
};
|
||||||
|
const props: string[] = (this as any).saveableProperties || [];
|
||||||
|
for (const keyName of props) {
|
||||||
|
const value = this[keyName];
|
||||||
|
result[keyName] = foldValue(value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,17 +162,7 @@ export const deepEqualObjects = (object1: any, object2: any): boolean => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deepEqualJsonLStrings = (jsonLString1: string, jsonLString2: string): boolean => {
|
export const deepEqualJsonLStrings = (jsonLString1: string, jsonLString2: string): boolean => {
|
||||||
const firstArray = [];
|
const firstArray = parseJsonL(jsonLString1);
|
||||||
jsonLString1.split('\n').forEach((line) => {
|
const secondArray = parseJsonL(jsonLString2);
|
||||||
if (line) {
|
|
||||||
firstArray.push(parse(line));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const secondArray = [];
|
|
||||||
jsonLString2.split('\n').forEach((line) => {
|
|
||||||
if (line) {
|
|
||||||
secondArray.push(parse(line));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return deepEqualObjects(firstArray, secondArray);
|
return deepEqualObjects(firstArray, secondArray);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user