Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
58322d23f4 | |||
2f012fc0ad | |||
9bb6e0b497 | |||
5275e13360 | |||
03fe2174d1 | |||
7df82ce64d | |||
09b74e4053 | |||
096cd74773 | |||
e9a45ac993 | |||
b3856cb94a | |||
e44d014733 | |||
777d7ae1b3 | |||
f1f6b5fa79 | |||
65673e9710 | |||
66f1094cfe | |||
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",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "current file",
|
"command": "npm test",
|
||||||
"type": "node",
|
"name": "Run npm test",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"args": [
|
"type": "node-terminal"
|
||||||
"${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"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
207
changelog.md
Normal file
207
changelog.md
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 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.
|
@@ -5,12 +5,28 @@
|
|||||||
"gitzone": {
|
"gitzone": {
|
||||||
"projectType": "npm",
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "code.foss.global",
|
||||||
"gitscope": "pushrocks",
|
"gitscope": "push.rocks",
|
||||||
"gitrepo": "smartjson",
|
"gitrepo": "smartjson",
|
||||||
"shortDescription": "typed json handlers",
|
"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.",
|
||||||
"npmPackagename": "@pushrocks/smartjson",
|
"npmPackagename": "@push.rocks/smartjson",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"JSON handling",
|
||||||
|
"typed JSON",
|
||||||
|
"JSON parsing",
|
||||||
|
"JSON stringifying",
|
||||||
|
"base64 encoding",
|
||||||
|
"buffer handling",
|
||||||
|
"data serialization",
|
||||||
|
"data deserialization",
|
||||||
|
"TypeScript support",
|
||||||
|
"data encoding",
|
||||||
|
"data decoding"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tsdoc": {
|
||||||
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
10624
package-lock.json
generated
10624
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@@ -1,37 +1,34 @@
|
|||||||
{
|
{
|
||||||
"name": "@pushrocks/smartjson",
|
"name": "@push.rocks/smartjson",
|
||||||
"version": "4.0.1",
|
"version": "5.0.21",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "typed json handlers",
|
"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",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/ --web)",
|
"test": "(tstest test/ --web)",
|
||||||
"build": "(tsbuild --web)"
|
"build": "(tsbuild --web --allowimplicitany)",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"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": {
|
||||||
"@gitzone/tsbuild": "^2.1.25",
|
"@git.zone/tsbuild": "^2.6.8",
|
||||||
"@gitzone/tsrun": "^1.2.12",
|
"@git.zone/tsrun": "^1.3.3",
|
||||||
"@gitzone/tstest": "^1.0.52",
|
"@git.zone/tstest": "^2.3.8",
|
||||||
"@pushrocks/tapbundle": "^3.2.9",
|
"@types/node": "^22"
|
||||||
"@types/node": "^14.11.2",
|
|
||||||
"tslint": "^6.1.3",
|
|
||||||
"tslint-config-prettier": "^1.18.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/buffer-json": "^2.0.0",
|
"@push.rocks/smartenv": "^5.0.13",
|
||||||
"@types/fast-json-stable-stringify": "^2.0.0",
|
"@push.rocks/smartstring": "^4.1.0",
|
||||||
"buffer-json": "^2.0.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"
|
||||||
},
|
},
|
||||||
@@ -49,5 +46,20 @@
|
|||||||
],
|
],
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 1 chrome versions"
|
"last 1 chrome versions"
|
||||||
]
|
],
|
||||||
|
"type": "module",
|
||||||
|
"keywords": [
|
||||||
|
"JSON handling",
|
||||||
|
"typed JSON",
|
||||||
|
"JSON parsing",
|
||||||
|
"JSON stringifying",
|
||||||
|
"base64 encoding",
|
||||||
|
"buffer handling",
|
||||||
|
"data serialization",
|
||||||
|
"data deserialization",
|
||||||
|
"TypeScript support",
|
||||||
|
"data encoding",
|
||||||
|
"data decoding"
|
||||||
|
],
|
||||||
|
"packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748"
|
||||||
}
|
}
|
||||||
|
8563
pnpm-lock.yaml
generated
Normal file
8563
pnpm-lock.yaml
generated
Normal file
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
|
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
368
readme.md
Normal file
368
readme.md
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
# @push.rocks/smartjson
|
||||||
|
**🚀 Typed JSON handling for modern Node.js and TypeScript applications**
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Using npm
|
||||||
|
npm install @push.rocks/smartjson --save
|
||||||
|
|
||||||
|
# Using yarn
|
||||||
|
yarn add @push.rocks/smartjson
|
||||||
|
|
||||||
|
# Using pnpm (recommended)
|
||||||
|
pnpm add @push.rocks/smartjson
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
✨ **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
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
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
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Functions
|
||||||
|
|
||||||
|
### JSON Parsing and Stringification
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Standard parsing with automatic Buffer detection
|
||||||
|
const obj = smartjson.parse('{"hello":"world"}');
|
||||||
|
|
||||||
|
// Stable stringification (consistent key ordering)
|
||||||
|
const jsonStr = smartjson.stringify({ name: 'test', id: 1 });
|
||||||
|
|
||||||
|
// Pretty printing for debugging
|
||||||
|
const prettyJson = smartjson.stringifyPretty({
|
||||||
|
nested: {
|
||||||
|
data: 'value'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Base64 JSON Encoding
|
||||||
|
|
||||||
|
Encode JSON data as base64 for safe transmission:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const myData = {
|
||||||
|
message: 'Hello World',
|
||||||
|
timestamp: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Lines (JSONL) Support
|
||||||
|
|
||||||
|
Perfect for streaming data and log processing:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Parse JSON Lines format
|
||||||
|
const jsonLines = `{"event":"start","time":1234}
|
||||||
|
{"event":"data","value":42}
|
||||||
|
{"event":"end","time":5678}`;
|
||||||
|
|
||||||
|
const events = smartjson.parseJsonL(jsonLines);
|
||||||
|
// Result: Array of parsed objects
|
||||||
|
|
||||||
|
// 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Class Serialization
|
||||||
|
|
||||||
|
### Creating Serializable Classes
|
||||||
|
|
||||||
|
Transform class instances to JSON and back while preserving type safety:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Smartjson, foldDec } from '@push.rocks/smartjson';
|
||||||
|
|
||||||
|
class User extends Smartjson {
|
||||||
|
@foldDec() public username: string;
|
||||||
|
@foldDec() public email: string;
|
||||||
|
@foldDec() public settings: UserSettings;
|
||||||
|
|
||||||
|
// Properties without @foldDec won't be serialized
|
||||||
|
private internalId: string;
|
||||||
|
|
||||||
|
constructor(username: string, email: string) {
|
||||||
|
super();
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class AppConfig extends Smartjson {
|
||||||
|
@foldDec() public apiUrl: string;
|
||||||
|
@foldDec() public features: Map<string, boolean> = new Map();
|
||||||
|
@foldDec() public limits: {
|
||||||
|
maxUploadSize: number;
|
||||||
|
maxConcurrentRequests: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
enableFeature(name: string) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### 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
|
||||||
|
- `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
|
||||||
|
// Before
|
||||||
|
JSON.parse(jsonString);
|
||||||
|
JSON.stringify(object);
|
||||||
|
|
||||||
|
// After
|
||||||
|
smartjson.parse(jsonString); // Adds buffer support
|
||||||
|
smartjson.stringify(object); // Adds stable ordering & buffer support
|
||||||
|
```
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
This library supports modern browsers and Node.js environments. For older browsers, ensure you have appropriate polyfills for `TextEncoder` and `TextDecoder`.
|
||||||
|
|
||||||
|
## License and Legal Information
|
||||||
|
|
||||||
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||||
|
|
||||||
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
### Trademarks
|
||||||
|
|
||||||
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||||
|
|
||||||
|
### Company Information
|
||||||
|
|
||||||
|
Task Venture Capital GmbH
|
||||||
|
Registered at District court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
75
test/test.both.ts
Normal file
75
test/test.both.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { tap, expect } from '@git.zone/tstest/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 @push.rocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@push.rocks/smartjson',
|
||||||
|
version: '5.0.21',
|
||||||
|
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.'
|
||||||
|
}
|
134
ts/bufferhandling.ts
Normal file
134
ts/bufferhandling.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
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 {
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 };
|
111
ts/index.ts
111
ts/index.ts
@@ -1,27 +1,67 @@
|
|||||||
import * as plugins from './smartjson.plugins';
|
import * as plugins from './smartjson.plugins.js';
|
||||||
|
import * as bufferhandling from './bufferhandling.js';
|
||||||
|
|
||||||
|
interface JsonObject {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* allows you to parse a json
|
* allows you to parse a json
|
||||||
*/
|
*/
|
||||||
export const parse = plugins.bufferJson.parse;
|
export const parse = bufferhandling.parse;
|
||||||
|
|
||||||
|
export const parseJsonL = (jsonlData: string): JsonObject[] => {
|
||||||
|
const lines = jsonlData.split('\n');
|
||||||
|
const parsedData: JsonObject[] = lines.reduce((acc, line) => {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (trimmed.length > 0) {
|
||||||
|
acc.push(parse(trimmed));
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, [] as JsonObject[]);
|
||||||
|
return parsedData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param objArg
|
* @param objArg
|
||||||
* @param optionsArg
|
* @param optionsArg
|
||||||
*/
|
*/
|
||||||
export const stringify = (objArg: any, optionsArg: plugins.IStableJsonTypes['Options'] = {}) => {
|
export const stringify = (
|
||||||
const bufferedJson = plugins.bufferJson.stringify(objArg);
|
objArg: any,
|
||||||
|
simpleOrderArray?: string[],
|
||||||
|
optionsArg: plugins.IStableJsonTypes['Options'] = {}
|
||||||
|
): string => {
|
||||||
|
const bufferedJson = bufferhandling.stringify(objArg);
|
||||||
objArg = JSON.parse(bufferedJson);
|
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 base64 = plugins.smartstring.base64 as any;
|
||||||
|
const decodeFn: (input: string) => string = base64.decodeUri || base64.decode;
|
||||||
|
const simpleStringified = decodeFn(base64JsonStringArg);
|
||||||
|
return parse(simpleStringified);
|
||||||
};
|
};
|
||||||
|
|
||||||
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>;
|
||||||
for (const keyName in objectArg) {
|
for (const keyName in objectArg) {
|
||||||
if (newInstance.saveableProperties.indexOf(keyName) !== -1) {
|
if (newInstance.saveableProperties.indexOf(keyName) !== -1) {
|
||||||
newInstance[keyName] = objectArg[keyName];
|
newInstance[keyName] = objectArg[keyName];
|
||||||
@@ -33,7 +73,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);
|
||||||
}
|
}
|
||||||
@@ -49,25 +89,62 @@ export class Smartjson {
|
|||||||
*/
|
*/
|
||||||
public foldToObject() {
|
public foldToObject() {
|
||||||
const newFoldedObject: { [key: string]: any } = {};
|
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) {
|
for (const keyName of this.saveableProperties) {
|
||||||
newFoldedObject[keyName] = plugins.lodashCloneDeep(this[keyName]);
|
const value = this[keyName];
|
||||||
|
newFoldedObject[keyName] = foldValue(value);
|
||||||
}
|
}
|
||||||
return newFoldedObject;
|
return newFoldedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
result[keyName] = foldValue(value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* folds a class into an object
|
* folds a class into an object
|
||||||
*/
|
*/
|
||||||
public foldToJson() {
|
public foldToJson() {
|
||||||
const foldedObject = this.foldToObject();
|
const foldedObject = this.foldToObject();
|
||||||
return stringify(foldedObject, {});
|
return stringify(foldedObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorator that marks a property as foldable
|
* Decorator that marks a property as foldable
|
||||||
*/
|
*/
|
||||||
export let foldDec = () => {
|
export const foldDec = () => {
|
||||||
return (target: any, key: string) => {
|
return (target: any, key: string) => {
|
||||||
if (!target.saveableProperties) {
|
if (!target.saveableProperties) {
|
||||||
target.saveableProperties = [];
|
target.saveableProperties = [];
|
||||||
@@ -75,3 +152,15 @@ export let foldDec = () => {
|
|||||||
target.saveableProperties.push(key);
|
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 = parseJsonL(jsonLString1);
|
||||||
|
const secondArray = parseJsonL(jsonLString2);
|
||||||
|
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
|
// third party scope
|
||||||
import lodashCloneDeep from 'lodash.clonedeep';
|
import lodashCloneDeep from 'lodash.clonedeep';
|
||||||
import stableJson2 from 'fast-json-stable-stringify';
|
import stableJson2 from 'fast-json-stable-stringify';
|
||||||
import bufferJson from 'buffer-json';
|
|
||||||
|
|
||||||
const stableJson = stableJson2 as any;
|
const stableJson = stableJson2 as any;
|
||||||
|
|
||||||
export { bufferJson, lodashCloneDeep, stableJson };
|
export { lodashCloneDeep, stableJson };
|
||||||
|
|
||||||
export interface IStableJsonTypes {
|
export interface IStableJsonTypes {
|
||||||
Comparator: (
|
Comparator: (
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"target": "es2017",
|
"verbatimModuleSyntax": true
|
||||||
"module": "commonjs"
|
},
|
||||||
}
|
"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