Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
8e93b8cb73 | |||
e38ccd221a | |||
969b892ed8 | |||
d1d679ac34 | |||
8937dfb553 | |||
09d45b1f45 | |||
a897f01ec6 | |||
f951e0e70d | |||
e79a2514ef | |||
d77c104915 | |||
45593168b0 | |||
0227f22ca6 | |||
cece00a9b0 | |||
e90ae7649f | |||
70e6150708 | |||
52928e0b9b | |||
00ae980fa7 | |||
2cd2180788 | |||
2a37a42ed0 | |||
e88deb1b5f | |||
05f8e6812b | |||
3affd81165 | |||
7a8f959cf4 | |||
4df1d41cc7 | |||
fb83e41eb3 | |||
27b67b63cc | |||
697afbaf98 | |||
ab3ae7ec90 | |||
b2bb918ee4 | |||
606ff73f58 | |||
7ea17c792d | |||
4478b7588a | |||
9bac6e5809 | |||
cbc7e4ebce | |||
097f54a74c | |||
807624d157 | |||
9d7e2e03d9 | |||
9686caff18 | |||
9260d653a1 | |||
28cd849d0d | |||
89a399bf42 | |||
16048fe96d | |||
04d60333a9 | |||
c30f1f4ab9 | |||
fc91dd3171 | |||
55f8951732 | |||
92f212e9d3 |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
name: Default (not tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags-ignore:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install pnpm and npmci
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @shipzone/npmci
|
||||
|
||||
- name: Run npm prepare
|
||||
run: npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@ -0,0 +1,124 @@
|
||||
name: Default (tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @shipzone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @shipzone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
||||
|
||||
release:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @shipzone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Release
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm publish
|
||||
|
||||
metadata:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @shipzone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Code quality
|
||||
run: |
|
||||
npmci command npm install -g typescript
|
||||
npmci npm install
|
||||
|
||||
- name: Trigger
|
||||
run: npmci trigger
|
||||
|
||||
- name: Build docs and upload artifacts
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
pnpm install -g @git.zone/tsdoc
|
||||
npmci command tsdoc
|
||||
continue-on-error: true
|
137
.gitlab-ci.yml
137
.gitlab-ci.yml
@ -1,137 +0,0 @@
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
4
.snyk
4
.snyk
@ -1,4 +0,0 @@
|
||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||
version: v1.13.3
|
||||
ignore: {}
|
||||
patch: {}
|
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@ -2,28 +2,10 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "current file",
|
||||
"type": "node",
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"${relativeFile}"
|
||||
],
|
||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"protocol": "inspector",
|
||||
"internalConsoleOptions": "openOnSessionStart"
|
||||
},
|
||||
{
|
||||
"name": "test.ts",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"test/test.ts"
|
||||
],
|
||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"protocol": "inspector",
|
||||
"internalConsoleOptions": "openOnSessionStart"
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"gitscope": "push.rocks",
|
||||
"gitrepo": "smartjson",
|
||||
"shortDescription": "typed json handlers",
|
||||
"npmPackagename": "@pushrocks/smartjson",
|
||||
"description": "typed json handlers",
|
||||
"npmPackagename": "@push.rocks/smartjson",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
10624
package-lock.json
generated
10624
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "@pushrocks/smartjson",
|
||||
"version": "4.0.1",
|
||||
"name": "@push.rocks/smartjson",
|
||||
"version": "5.0.16",
|
||||
"private": false,
|
||||
"description": "typed json handlers",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "(tstest test/ --web)",
|
||||
"build": "(tsbuild --web)"
|
||||
"build": "(tsbuild --web --allowimplicitany)",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -20,18 +21,16 @@
|
||||
},
|
||||
"homepage": "https://gitlab.com/pushrocks/smartjson#README",
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.1.25",
|
||||
"@gitzone/tsrun": "^1.2.12",
|
||||
"@gitzone/tstest": "^1.0.52",
|
||||
"@pushrocks/tapbundle": "^3.2.9",
|
||||
"@types/node": "^14.11.2",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
"@git.zone/tsbuild": "^2.1.66",
|
||||
"@git.zone/tsrun": "^1.2.44",
|
||||
"@git.zone/tstest": "^1.0.77",
|
||||
"@push.rocks/tapbundle": "^5.0.8",
|
||||
"@types/node": "^20.11.24"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/buffer-json": "^2.0.0",
|
||||
"@types/fast-json-stable-stringify": "^2.0.0",
|
||||
"buffer-json": "^2.0.0",
|
||||
"@push.rocks/smartbuffer": "^1.0.7",
|
||||
"@push.rocks/smartenv": "^5.0.12",
|
||||
"@push.rocks/smartstring": "^4.0.14",
|
||||
"fast-json-stable-stringify": "^2.1.0",
|
||||
"lodash.clonedeep": "^4.5.0"
|
||||
},
|
||||
@ -49,5 +48,6 @@
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
],
|
||||
"type": "module"
|
||||
}
|
||||
|
5685
pnpm-lock.yaml
generated
Normal file
5685
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
64
readme.md
Normal file
64
readme.md
Normal file
@ -0,0 +1,64 @@
|
||||
# @push.rocks/smartjson
|
||||
typed json handlers
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@push.rocks/smartjson)
|
||||
* [gitlab.com (source)](https://gitlab.com/push.rocks/smartjson)
|
||||
* [github.com (source mirror)](https://github.com/push.rocks/smartjson)
|
||||
* [docs (typedoc)](https://push.rocks.gitlab.io/smartjson/)
|
||||
|
||||
## Status for master
|
||||
|
||||
Status Category | Status Badge
|
||||
-- | --
|
||||
GitLab Pipelines | [](https://lossless.cloud)
|
||||
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||
npm | [](https://lossless.cloud)
|
||||
Snyk | [](https://lossless.cloud)
|
||||
TypeScript Support | [](https://lossless.cloud)
|
||||
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
Code Style | [](https://lossless.cloud)
|
||||
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||
|
||||
## Usage
|
||||
|
||||
Use TypeScript for best in class instellisense.
|
||||
|
||||
### Classes
|
||||
|
||||
SmartJson makes it easy to fold and enfold classes into and from JSON
|
||||
|
||||
```javascript
|
||||
import { Smartjson, foldDec } from 'smartjson';
|
||||
|
||||
class AwesomeClass extends Smartjson {
|
||||
static stringify;
|
||||
|
||||
computedValue: string;
|
||||
|
||||
@foldDec() // mark anotherValueToStore as foldable
|
||||
anotherValueToStore: string = null;
|
||||
constructor() {
|
||||
super(); // this is important
|
||||
}
|
||||
}
|
||||
|
||||
let myAwesomeInstance = new AwesomeClass();
|
||||
let foldedObject = myAwesomeInstance.foldToObject(); // will return {anotherValueToStore: null}
|
||||
// You can also fold to Json, with support for buffers
|
||||
// const jsonString = myAwesomeInstance.foldToJson();
|
||||
myAwesomeInstance = AwesomeClass.enfoldFromObject({ anotherValueToStore: 'hi' });
|
||||
foldedObject = myAwesomeInstance.foldToObject(); // will return {anotherValueToStore: 'hi'}
|
||||
```
|
||||
|
||||
## Contribution
|
||||
|
||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
|
||||
## Legal
|
||||
> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
75
test/test.both.ts
Normal file
75
test/test.both.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { tap, expect } from '@push.rocks/tapbundle';
|
||||
|
||||
import * as smartjson from '../ts/index.js';
|
||||
|
||||
class SomeClass extends smartjson.Smartjson {
|
||||
@smartjson.foldDec() thisis: string = 'test';
|
||||
constructor() {
|
||||
super();
|
||||
console.log(this.saveableProperties);
|
||||
}
|
||||
}
|
||||
|
||||
let mySomeClass: SomeClass;
|
||||
|
||||
tap.test('should create a Foldable extended instance', async () => {
|
||||
mySomeClass = new SomeClass();
|
||||
expect(mySomeClass).toBeInstanceOf(SomeClass);
|
||||
expect(mySomeClass).toBeInstanceOf(smartjson.Smartjson);
|
||||
});
|
||||
|
||||
tap.test('should create a folded object', async () => {
|
||||
let foldedObject = mySomeClass.foldToObject();
|
||||
expect(foldedObject).property('thisis').toEqual('test');
|
||||
});
|
||||
|
||||
tap.test('should enfold from object', async () => {
|
||||
const mySomeClass2 = SomeClass.enfoldFromObject({ thisis: 'test2' });
|
||||
expect(mySomeClass2).property('thisis').toEqual('test2');
|
||||
});
|
||||
|
||||
tap.test('should products stable jsons', async () => {
|
||||
const jsonString = smartjson.stringify({
|
||||
a: 1,
|
||||
f: 6,
|
||||
b: 3,
|
||||
c: 3,
|
||||
e: 5,
|
||||
d: 4,
|
||||
});
|
||||
console.log(jsonString);
|
||||
});
|
||||
|
||||
tap.test('should work with base64', async () => {
|
||||
const someObject = {
|
||||
hi: 'there',
|
||||
thisIs: 'awesome',
|
||||
};
|
||||
|
||||
const base64Json = smartjson.stringifyBase64(someObject);
|
||||
console.log(base64Json);
|
||||
const decodedObject = smartjson.parseBase64(base64Json);
|
||||
expect(decodedObject).toEqual(someObject);
|
||||
});
|
||||
|
||||
tap.test('stringify should handle plain string', async () => {
|
||||
const stringifiedString = smartjson.stringify('hello');
|
||||
console.log(stringifiedString);
|
||||
expect(stringifiedString).toEqual('"hello"');
|
||||
expect(smartjson.parse(stringifiedString)).toEqual('hello');
|
||||
});
|
||||
|
||||
tap.test('should work with buffers', async () => {
|
||||
const someObject = {
|
||||
myBuffer: new TextEncoder().encode('hello')
|
||||
};
|
||||
console.log(someObject.myBuffer);
|
||||
const stringified = smartjson.stringify(someObject);
|
||||
console.log(stringified);
|
||||
const decoded = smartjson.parse(stringified);
|
||||
console.log(decoded.myBuffer);
|
||||
let text = new TextDecoder().decode(decoded.myBuffer);
|
||||
expect(text).toEqual('hello');
|
||||
});
|
||||
|
||||
tap.start();
|
31
test/test.ts
31
test/test.ts
@ -1,31 +0,0 @@
|
||||
import { tap, expect } from '@pushrocks/tapbundle';
|
||||
|
||||
import { Smartjson, foldDec } from '../ts/index';
|
||||
|
||||
class SomeClass extends Smartjson {
|
||||
@foldDec() thisis: string = 'test';
|
||||
constructor() {
|
||||
super();
|
||||
console.log(this.saveableProperties);
|
||||
}
|
||||
}
|
||||
|
||||
let mySomeClass: SomeClass;
|
||||
|
||||
tap.test('should create a Foldable extended instance', async () => {
|
||||
mySomeClass = new SomeClass();
|
||||
expect(mySomeClass).to.be.instanceof(SomeClass);
|
||||
expect(mySomeClass).to.be.instanceof(Smartjson);
|
||||
});
|
||||
|
||||
tap.test('should create a folded object', async () => {
|
||||
let foldedObject = mySomeClass.foldToObject();
|
||||
expect(foldedObject).property('thisis').to.equal('test');
|
||||
});
|
||||
|
||||
tap.test('should enfold from object', async () => {
|
||||
const mySomeClass2 = SomeClass.enfoldFromObject({ thisis: 'test2' });
|
||||
expect(mySomeClass2).property('thisis').to.equal('test2');
|
||||
});
|
||||
|
||||
tap.start();
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartjson',
|
||||
version: '5.0.16',
|
||||
description: 'typed json handlers'
|
||||
}
|
121
ts/bufferhandling.ts
Normal file
121
ts/bufferhandling.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import * as plugins from './smartjson.plugins.js';
|
||||
|
||||
// Define interfaces and types for better type checking and readability
|
||||
interface IBufferLike {
|
||||
type: 'Buffer';
|
||||
data: string | any[]; // `any[]` for array data representation
|
||||
}
|
||||
|
||||
interface IEncodedBuffer {
|
||||
type: 'EncodedBuffer',
|
||||
data: string;
|
||||
}
|
||||
|
||||
type TParseReviver = (this: any, key: string, value: any) => any;
|
||||
type TParseReplacer = (this: any, key: string, value: any) => any;
|
||||
|
||||
// Utility functions to handle base64 encoding/decoding in a cross-platform way
|
||||
function base64Encode(data: Uint8Array): string {
|
||||
return btoa(String.fromCharCode(...data));
|
||||
}
|
||||
|
||||
function base64Decode(str: string): Uint8Array {
|
||||
return new Uint8Array(Array.from(atob(str)).map((char) => char.charCodeAt(0)));
|
||||
}
|
||||
|
||||
// Main functionality with cross-platform support
|
||||
function stringify(value: any, space?: string | number): string {
|
||||
return JSON.stringify(value, replacer, space);
|
||||
}
|
||||
|
||||
function parse(text: string): any {
|
||||
return JSON.parse(text, reviver);
|
||||
}
|
||||
|
||||
const replacer: TParseReplacer = (key, value) => {
|
||||
// Check if value is IBufferLike
|
||||
if (isBufferLike(value)) {
|
||||
let bufferData: Uint8Array;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
// Handle Uint8Array directly
|
||||
else if (value instanceof Uint8Array) {
|
||||
bufferData = value;
|
||||
} else {
|
||||
// If not a recognized format, return value as is
|
||||
return value;
|
||||
}
|
||||
|
||||
// Encode the bufferData (Uint8Array) to base64
|
||||
const base64Data = 'base64:' + base64Encode(bufferData);
|
||||
return {
|
||||
type: 'EncodedBuffer',
|
||||
data: base64Data,
|
||||
};
|
||||
}
|
||||
|
||||
// Return value unchanged if not buffer-like
|
||||
return value;
|
||||
};
|
||||
|
||||
const reviver: TParseReviver = (key, value) => {
|
||||
if (isEncodedBuffer(value)) {
|
||||
if (isString(value.data) && value.data.startsWith('base64:')) {
|
||||
// Correctly slice the 'base64:' prefix before decoding
|
||||
const base64Data = value.data.slice(7); // Skip 'base64:' prefix
|
||||
const buffer = base64Decode(base64Data);
|
||||
// Assuming the rest of your application can work directly with Uint8Array,
|
||||
// otherwise, you might need to convert it to another format
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
function isEncodedBuffer(x: any): x is IEncodedBuffer {
|
||||
return isObject(x) && (x as any).type === 'EncodedBuffer' && isString((x as any).data);
|
||||
}
|
||||
|
||||
function isBufferLike(x: any): x is IBufferLike | Uint8Array {
|
||||
return (
|
||||
(isObject(x) &&
|
||||
((x as any).type === 'Buffer' &&
|
||||
(isArray((x as any).data) || isString((x as any).data)))) ||
|
||||
x instanceof Uint8Array
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We use this function to check if a value is an array
|
||||
* @param x
|
||||
* @returns
|
||||
*/
|
||||
function isArray(x: any): x is any[] {
|
||||
return Array.isArray(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* We use this function to check if a value is a string
|
||||
* @param x
|
||||
* @returns
|
||||
*/
|
||||
function isString(x: any): x is string {
|
||||
return typeof x === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* We use this function to check if a value is an object
|
||||
* @param x
|
||||
*/
|
||||
function isObject(x: any): x is object {
|
||||
return typeof x === 'object' && x !== null;
|
||||
}
|
||||
|
||||
export { stringify, parse, replacer, reviver };
|
72
ts/index.ts
72
ts/index.ts
@ -1,21 +1,46 @@
|
||||
import * as plugins from './smartjson.plugins';
|
||||
import * as plugins from './smartjson.plugins.js';
|
||||
import * as bufferhandling from './bufferhandling.js';
|
||||
import { json } from 'stream/consumers';
|
||||
|
||||
/**
|
||||
* allows you to parse a json
|
||||
*/
|
||||
export const parse = plugins.bufferJson.parse;
|
||||
export const parse = bufferhandling.parse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param objArg
|
||||
* @param optionsArg
|
||||
*/
|
||||
export const stringify = (objArg: any, optionsArg: plugins.IStableJsonTypes['Options'] = {}) => {
|
||||
const bufferedJson = plugins.bufferJson.stringify(objArg);
|
||||
export const stringify = (
|
||||
objArg: any,
|
||||
simpleOrderArray?: string[],
|
||||
optionsArg: plugins.IStableJsonTypes['Options'] = {}
|
||||
): string => {
|
||||
const bufferedJson = bufferhandling.stringify(objArg);
|
||||
objArg = JSON.parse(bufferedJson);
|
||||
return plugins.stableJson(objArg, optionsArg);
|
||||
let returnJson = plugins.stableJson(objArg, optionsArg);
|
||||
return returnJson;
|
||||
};
|
||||
|
||||
export const stringifyPretty = (objectArg: any) => {
|
||||
const stringified = stringify(objectArg);
|
||||
const object = JSON.parse(stringified);
|
||||
return JSON.stringify(object, null, 2);
|
||||
}
|
||||
|
||||
export const stringifyBase64 = (...args: Parameters<typeof stringify>): string => {
|
||||
const stringifiedResult = stringify(...args);
|
||||
return plugins.smartstring.base64.encodeUri(stringifiedResult);
|
||||
};
|
||||
|
||||
export const parseBase64 = (base64JsonStringArg: string) => {
|
||||
const simpleStringified = plugins.smartstring.base64.decode(base64JsonStringArg);
|
||||
return parse(simpleStringified);
|
||||
};
|
||||
|
||||
parse;
|
||||
|
||||
export class Smartjson {
|
||||
/**
|
||||
* enfolds data from an object
|
||||
@ -49,8 +74,17 @@ export class Smartjson {
|
||||
*/
|
||||
public foldToObject() {
|
||||
const newFoldedObject: { [key: string]: any } = {};
|
||||
const trackMap = [];
|
||||
for (const keyName of this.saveableProperties) {
|
||||
newFoldedObject[keyName] = plugins.lodashCloneDeep(this[keyName]);
|
||||
let value = this[keyName];
|
||||
if (value instanceof Smartjson) {
|
||||
if (trackMap.includes(value)) {
|
||||
throw new Error('cycle detected');
|
||||
}
|
||||
trackMap.push(value);
|
||||
value = value.foldToObject();
|
||||
}
|
||||
newFoldedObject[keyName] = plugins.lodashCloneDeep(value);
|
||||
}
|
||||
return newFoldedObject;
|
||||
}
|
||||
@ -60,14 +94,14 @@ export class Smartjson {
|
||||
*/
|
||||
public foldToJson() {
|
||||
const foldedObject = this.foldToObject();
|
||||
return stringify(foldedObject, {});
|
||||
return stringify(foldedObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorator that marks a property as foldable
|
||||
*/
|
||||
export let foldDec = () => {
|
||||
export const foldDec = () => {
|
||||
return (target: any, key: string) => {
|
||||
if (!target.saveableProperties) {
|
||||
target.saveableProperties = [];
|
||||
@ -75,3 +109,25 @@ export let foldDec = () => {
|
||||
target.saveableProperties.push(key);
|
||||
};
|
||||
};
|
||||
|
||||
export const deepEqualObjects = (object1: any, object2: any): boolean => {
|
||||
const object1String = stringify(object1);
|
||||
const object2String = stringify(object2);
|
||||
return object1String === object2String;
|
||||
};
|
||||
|
||||
export const deepEqualJsonLStrings = (jsonLString1: string, jsonLString2: string): boolean => {
|
||||
const firstArray = [];
|
||||
jsonLString1.split('\n').forEach((line) => {
|
||||
if (line) {
|
||||
firstArray.push(parse(line));
|
||||
}
|
||||
});
|
||||
const secondArray = [];
|
||||
jsonLString2.split('\n').forEach((line) => {
|
||||
if (line) {
|
||||
secondArray.push(parse(line));
|
||||
}
|
||||
});
|
||||
return deepEqualObjects(firstArray, secondArray);
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
// @pushrocks scope
|
||||
import * as smartenv from '@push.rocks/smartenv';
|
||||
import * as smartstring from '@push.rocks/smartstring';
|
||||
|
||||
export { smartenv, smartstring };
|
||||
|
||||
// third party scope
|
||||
import lodashCloneDeep from 'lodash.clonedeep';
|
||||
import stableJson2 from 'fast-json-stable-stringify';
|
||||
import bufferJson from 'buffer-json';
|
||||
|
||||
const stableJson = stableJson2 as any;
|
||||
|
||||
export { bufferJson, lodashCloneDeep, stableJson };
|
||||
export { lodashCloneDeep, stableJson };
|
||||
|
||||
export interface IStableJsonTypes {
|
||||
Comparator: (
|
||||
|
@ -1,8 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"target": "es2017",
|
||||
"module": "commonjs"
|
||||
}
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
17
tslint.json
17
tslint.json
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
Reference in New Issue
Block a user