Skip to content

Commit 4201463

Browse files
committed
Add: json-safe-extend package
1 parent 298bd0f commit 4201463

File tree

9 files changed

+531
-0
lines changed

9 files changed

+531
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<br>
2+
<div align="center">
3+
4+
<p align="center">Deeply extend JSON-safe objects ~300B</p>
5+
6+
<p align="center">
7+
<a aria-label="overview" href="https://github.com/techor-dev/techor">
8+
<picture>
9+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/%E2%AC%85%20back-%20?color=212022&style=for-the-badge">
10+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/badge/%E2%AC%85%20back-%20?color=f6f7f8&style=for-the-badge">
11+
<img alt="NPM Version" src="https://img.shields.io/badge/%E2%AC%85%20back-%20?color=f6f7f8&style=for-the-badge">
12+
</picture>
13+
</a>
14+
<a aria-label="GitHub release (latest by date including pre-releases)" href="https://github.com/techor-dev/techor/releases">
15+
<picture>
16+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/v/release/techor-dev/techor?include_prereleases&color=212022&label=&style=for-the-badge&logo=github&logoColor=fff">
17+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/v/release/techor-dev/techor?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github&logoColor=%23000">
18+
<img alt="NPM Version" src="https://img.shields.io/github/v/release/techor-dev/techor?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github">
19+
</picture>
20+
</a>
21+
<a aria-label="NPM Package" href="https://www.npmjs.com/package/json-safe-extend">
22+
<picture>
23+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/json-safe-extend?color=212022&label=%20&logo=npm&style=for-the-badge">
24+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/json-safe-extend?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
25+
<img alt="NPM package ( download / month )" src="https://img.shields.io/npm/dm/json-safe-extend?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
26+
</picture>
27+
</a>
28+
<a aria-label="Follow @aron1tw" href="https://twitter.com/aron1tw">
29+
<picture>
30+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=212022&logo=twitter&style=for-the-badge">
31+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
32+
<img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
33+
</picture>
34+
</a>
35+
<a aria-label="Github Actions" href="https://github.com/techor-dev/techor/actions/workflows/release.yml">
36+
<picture>
37+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/techor-dev/techor/release.yml?branch=main&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
38+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/techor-dev/techor/release.yml?branch=main&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
39+
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/techor-dev/techor/release.yml?branch=main&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
40+
</picture>
41+
</a>
42+
</p>
43+
44+
</div>
45+
46+
<br>
47+
48+
- Deeply extend
49+
- JSON-safe
50+
- Supports `Symbol`
51+
52+
<br>
53+
54+
## Getting Started
55+
56+
```bash
57+
npm install json-safe-extend
58+
```
59+
60+
## Usage
61+
```js
62+
import extend from 'json-safe-extend'
63+
64+
extend({ a: 1, b:2 }, { b: null, c:3 })
65+
// { a:1, b: null, c:3 }
66+
```
67+
68+
## Overview
69+
```js
70+
expect(
71+
extend(
72+
{
73+
a: 1,
74+
b: 2,
75+
d: {
76+
a: 1,
77+
b: [],
78+
c: { test1: 123, test2: 321 }
79+
},
80+
f: 5,
81+
g: 123,
82+
i: 321,
83+
j: [1, 2]
84+
},
85+
{
86+
b: 3,
87+
c: 5,
88+
d: {
89+
b: { first: 'one', second: 'two' },
90+
c: { test2: 222 }
91+
},
92+
e: { one: 1, two: 2 },
93+
f: [],
94+
g: (void 0),
95+
i: null,
96+
j: [3, 4]
97+
}
98+
)
99+
)
100+
.toEqual({
101+
a: 1,
102+
b: 3,
103+
d:
104+
{
105+
a: 1,
106+
b: { first: 'one', second: 'two' },
107+
c: { test1: 123, test2: 222 }
108+
},
109+
f: [],
110+
g: undefined,
111+
c: 5,
112+
e: { one: 1, two: 2 },
113+
i: null,
114+
j: [3, 4]
115+
})
116+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import common from '../../eslint.config.mjs'
2+
3+
export default common
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('jest').Config} */
2+
export default {
3+
preset: '@techor/jest'
4+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "json-safe-extend",
3+
"type": "module",
4+
"scripts": {
5+
"build:main": "rollup --config rollup.config.mjs",
6+
"build:type": "tsc --emitDeclarationOnly --preserveWatchOutput --project tsconfig.prod.json",
7+
"build": "pnpm run \"/^build:.*/\"",
8+
"dev": "pnpm run \"/^build:.*/\" --watch",
9+
"test": "jest",
10+
"type-check": "tsc --noEmit",
11+
"lint": "eslint"
12+
},
13+
"license": "MIT",
14+
"description": "Deeply extend JSON-safe objects",
15+
"author": {
16+
"name": "Aron",
17+
"email": "i@aron.tw",
18+
"url": "http://aron.tw"
19+
},
20+
"homepage": "https://aron.tw",
21+
"bugs": {
22+
"url": "https://github.com/techor-dev/techor/issues"
23+
},
24+
"repository": {
25+
"type": "git",
26+
"url": "https://github.com/techor-dev/techor.git",
27+
"directory": "packages/json-safe-extend"
28+
},
29+
"keywords": [
30+
"json-safe-extend",
31+
"merge",
32+
"deeply",
33+
"utils"
34+
],
35+
"sideEffects": false,
36+
"publishConfig": {
37+
"access": "public",
38+
"provenance": true
39+
},
40+
"main": "./dist/index.cjs",
41+
"esnext": "./dist/index.mjs",
42+
"module": "./dist/index.mjs",
43+
"types": "./dist/index.d.ts",
44+
"exports": {
45+
".": {
46+
"types": "./dist/index.d.ts",
47+
"require": "./dist/index.cjs",
48+
"import": "./dist/index.mjs"
49+
}
50+
},
51+
"files": [
52+
"dist"
53+
]
54+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import defineConfig from '../../rollup.config.mjs'
2+
3+
/** @type {import('rollup').RollupOptions} */
4+
export default {
5+
...defineConfig()
6+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export default function extend<T extends object>(...sources: Partial<T>[]): T {
2+
const target: any = {}
3+
4+
for (const obj of sources) {
5+
if (typeof obj !== 'object' || obj === null) continue
6+
7+
for (const key of Reflect.ownKeys(obj)) {
8+
const val = obj[key]
9+
const src = target[key]
10+
11+
if (val === target) continue
12+
13+
if (Array.isArray(val)) {
14+
target[key] = val.map(item =>
15+
typeof item === 'object' && item !== null
16+
? extend({}, item)
17+
: item
18+
)
19+
} else if (
20+
typeof val === 'object' &&
21+
val !== null &&
22+
!Array.isArray(val)
23+
) {
24+
target[key] =
25+
typeof src === 'object' && src !== null && !Array.isArray(src)
26+
? extend(src, val)
27+
: extend({}, val)
28+
} else {
29+
target[key] = val
30+
}
31+
}
32+
}
33+
34+
return target
35+
}

0 commit comments

Comments
 (0)