jfather 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +277 -228
- package/package.json +40 -31
- package/src/index.js +4 -0
- package/src/jfather.js +22 -19
- package/types/index.d.ts +1 -0
- package/types/jfather.d.ts +2 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -2,20 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Utiliser du HTML (avec l'attribut "align" obsolète) pour faire flotter
|
|
4
4
|
l'image à droite. -->
|
|
5
|
-
<!-- markdownlint-disable-next-line no-inline-html-->
|
|
6
|
-
<img src="asset/logo.svg" align="right" alt="">
|
|
5
|
+
<!-- markdownlint-disable-next-line no-inline-html -->
|
|
6
|
+
<img src="asset/logo.svg" align="right" width="100" height="100" alt="">
|
|
7
7
|
|
|
8
|
-
[![npm][img-npm]][link-npm]
|
|
9
|
-
[![
|
|
10
|
-
[![coverage][img-coverage]][link-coverage]
|
|
11
|
-
[![semver][img-semver]][link-semver]
|
|
8
|
+
[![npm][img-npm]][link-npm] [![build][img-build]][link-build]
|
|
9
|
+
[![coverage][img-coverage]][link-coverage] [![semver][img-semver]][link-semver]
|
|
12
10
|
|
|
13
11
|
> _Boys use JSON; Men use JFather._
|
|
14
12
|
|
|
15
13
|
## Overview
|
|
16
14
|
|
|
17
|
-
JFather is a
|
|
18
|
-
[JSON](https://www.json.org/json-en.html "JavaScript Object Notation")
|
|
15
|
+
JFather is a
|
|
16
|
+
[JSON](https://www.json.org/json-en.html "JavaScript Object Notation") utility
|
|
17
|
+
library to:
|
|
18
|
+
|
|
19
|
+
- [**merge**](#merge) deeply two JSON objects.
|
|
20
|
+
- [**extend**](#extend) a JSON objects with `"$extends"` property.
|
|
21
|
+
- [**override**](#override) an array with `"$foo[0]"` (replace a value) or
|
|
22
|
+
`"$foo[]"` (append values) properties.
|
|
19
23
|
|
|
20
24
|
<!-- prettier-ignore-start -->
|
|
21
25
|
```javascript
|
|
@@ -48,8 +52,8 @@ console.log(extended);
|
|
|
48
52
|
// "quote": "With great fist comes great KO"
|
|
49
53
|
// }
|
|
50
54
|
|
|
51
|
-
// Override an object.
|
|
52
|
-
const overridden =
|
|
55
|
+
// Override arrays of an object.
|
|
56
|
+
const overridden = JFather.merge(
|
|
53
57
|
{ "foo": ["a", "alpha"] },
|
|
54
58
|
{ "$foo[0]": "A", "$foo[]": ["BETA"] }
|
|
55
59
|
);
|
|
@@ -89,7 +93,7 @@ JFather is published on [npm][link-npm] (its CDN:
|
|
|
89
93
|
[esm.sh](https://esm.sh/jfather),
|
|
90
94
|
[jsDelivr](https://www.jsdelivr.com/package/npm/jfather),
|
|
91
95
|
[UNPKG](https://unpkg.com/browse/jfather/)) and
|
|
92
|
-
[
|
|
96
|
+
[JSR](https://jsr.io/@regseb/jfather).
|
|
93
97
|
|
|
94
98
|
```javascript
|
|
95
99
|
// Node.js and Bun (after `npm install jfather`):
|
|
@@ -100,263 +104,308 @@ import JFather from "https://esm.sh/jfather@0";
|
|
|
100
104
|
import JFather from "https://cdn.jsdelivr.net/npm/jfather@0";
|
|
101
105
|
import JFather from "https://unpkg.com/jfather@0";
|
|
102
106
|
|
|
103
|
-
// Deno:
|
|
104
|
-
import JFather from "
|
|
107
|
+
// Deno (after `deno add jsr:@regseb/jfather`):
|
|
108
|
+
import JFather from "jsr:@regseb/jfather";
|
|
105
109
|
```
|
|
106
110
|
|
|
107
111
|
## Features
|
|
108
112
|
|
|
109
113
|
### Merge
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"baz": "BETA"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
"foo":
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
115
|
+
With any two variable types (except objects), merge returns the value of the
|
|
116
|
+
child. The following example shows how to use it with numbers: the result is `2`
|
|
117
|
+
(retrieved from the child value).
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
const parent = 1;
|
|
121
|
+
const child = 2;
|
|
122
|
+
console.log(JFather.merge(parent, child));
|
|
123
|
+
// 2
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If both variables are objects, the object properties are merged one by one. In
|
|
127
|
+
this example, the `"foo"` property overwrites that of the parent. The properties
|
|
128
|
+
`"bar"` and `"baz"` are simply copied, as they are only in either the parent or
|
|
129
|
+
the child.
|
|
130
|
+
|
|
131
|
+
<!-- prettier-ignore-start -->
|
|
132
|
+
```javascript
|
|
133
|
+
const parent = { "foo": "alpha", "bar": "ALPHA" };
|
|
134
|
+
const child = { "foo": "beta", "baz": "BETA" };
|
|
135
|
+
console.log(JFather.merge(parent, child));
|
|
136
|
+
// { "foo": "beta", "bar": "ALPHA", "baz": "BETA" }
|
|
137
|
+
```
|
|
138
|
+
<!-- prettier-ignore-end -->
|
|
139
|
+
|
|
140
|
+
Merging is done recursively. The following example shows the merging of two
|
|
141
|
+
objects, which in turn contains the merging of the `"foo"` sub-objects.
|
|
142
|
+
|
|
143
|
+
<!-- prettier-ignore-start -->
|
|
144
|
+
```javascript
|
|
145
|
+
const parent = {
|
|
146
|
+
"foo": { "bar": 1, "baz": 2 },
|
|
147
|
+
"qux": "a"
|
|
148
|
+
};
|
|
149
|
+
const child = {
|
|
150
|
+
"foo": { "bar": 10, "quux": 20 },
|
|
151
|
+
"corge": "b"
|
|
152
|
+
};
|
|
153
|
+
console.log(JFather.merge(parent, child));
|
|
154
|
+
// {
|
|
155
|
+
// "foo": { "bar": 10, "baz": 2, "quux": 20 },
|
|
156
|
+
// "qux": "a",
|
|
157
|
+
// "corge": "b"
|
|
158
|
+
// }
|
|
159
|
+
```
|
|
160
|
+
<!-- prettier-ignore-end -->
|
|
161
|
+
|
|
162
|
+
Arrays are processed like any other type: the value of the child overrides that
|
|
163
|
+
of the parent. For more detailed merging, see the [_Override_](#override)
|
|
164
|
+
chapter, which shows how to merge arrays.
|
|
165
|
+
|
|
166
|
+
<!-- prettier-ignore-start -->
|
|
167
|
+
```javascript
|
|
168
|
+
const parent = { "foo": [1, 10, 11] };
|
|
169
|
+
const child = { "foo": [2, 20, 22] };
|
|
170
|
+
console.log(JFather.merge(parent, child));
|
|
171
|
+
// { "foo": [2, 20, 22] }
|
|
172
|
+
```
|
|
173
|
+
<!-- prettier-ignore-end -->
|
|
151
174
|
|
|
152
175
|
### Extend
|
|
153
176
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
<td><pre lang="json"><code>{
|
|
202
|
-
"quux": {
|
|
203
|
-
"$extends": "https://foo.bar/parent.json",
|
|
204
|
-
"corge": "grault"
|
|
205
|
-
}
|
|
206
|
-
}</code></pre></td>
|
|
207
|
-
<td><pre lang="json"><code>{
|
|
208
|
-
"quux": {
|
|
209
|
-
"baz": "qux",
|
|
210
|
-
"corge": "grault"
|
|
177
|
+
You can extend an object using the `"$extends"` property, which must link to a
|
|
178
|
+
JSON file. The remote JSON file and the current object will be merged.
|
|
179
|
+
|
|
180
|
+
In this example, the child object is empty (except for the `"$extends"`
|
|
181
|
+
property). The result therefore contains the parent object.
|
|
182
|
+
|
|
183
|
+
<!-- prettier-ignore-start -->
|
|
184
|
+
```javascript
|
|
185
|
+
// https://example.com/parent.json
|
|
186
|
+
// { "foo": 42 }
|
|
187
|
+
|
|
188
|
+
const obj = { "$extends": "https://example.com/parent.json" };
|
|
189
|
+
console.log(await JFather.extend(obj));
|
|
190
|
+
// { "foo": 42 }
|
|
191
|
+
```
|
|
192
|
+
<!-- prettier-ignore-end -->
|
|
193
|
+
|
|
194
|
+
As with merge, if a property is in both parent and child, the child's value is
|
|
195
|
+
used. Otherwise, both parent and child properties are added to the result.
|
|
196
|
+
|
|
197
|
+
<!-- prettier-ignore-start -->
|
|
198
|
+
```javascript
|
|
199
|
+
// https://example.com/parent.json
|
|
200
|
+
// { "foo": "A", "bar": "Alpha" }
|
|
201
|
+
|
|
202
|
+
const obj = {
|
|
203
|
+
"$extends": "https://example.com/parent.json",
|
|
204
|
+
"foo": "B",
|
|
205
|
+
"baz": "Beta"
|
|
206
|
+
};
|
|
207
|
+
console.log(await JFather.extend(obj));
|
|
208
|
+
// { "foo": "B", "bar": "Alpha", "baz": "Beta" }
|
|
209
|
+
```
|
|
210
|
+
<!-- prettier-ignore-end -->
|
|
211
|
+
|
|
212
|
+
It is possible to extend a child's sub-object. In the example below, the parent
|
|
213
|
+
is merged with the child's `"bar"` sub-object.
|
|
214
|
+
|
|
215
|
+
<!-- prettier-ignore-start -->
|
|
216
|
+
```javascript
|
|
217
|
+
// https://example.com/parent.json
|
|
218
|
+
// { "foo": 42 }
|
|
219
|
+
|
|
220
|
+
const obj = {
|
|
221
|
+
"bar": {
|
|
222
|
+
"$extends": "https://example.com/parent.json",
|
|
223
|
+
"baz": 3.14
|
|
211
224
|
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
225
|
+
};
|
|
226
|
+
console.log(await JFather.extend(obj));
|
|
227
|
+
// {
|
|
228
|
+
// "bar": { "foo": 42, "baz": 3.14 }
|
|
229
|
+
// }
|
|
230
|
+
```
|
|
231
|
+
<!-- prettier-ignore-end -->
|
|
232
|
+
|
|
233
|
+
In the parent link, you can define a path to retrieve a sub-object from the
|
|
234
|
+
parent. The path is set in the URL hash:
|
|
235
|
+
|
|
236
|
+
- `#foo`: the value of the `"foo"` property;
|
|
237
|
+
- `#foo.bar`: the value of the `"bar"` sub-property in the `"foo"` property;
|
|
238
|
+
- `#foo[42]`: the value of the forty-third array element in the `"foo"`
|
|
239
|
+
property;
|
|
240
|
+
- `#foo[0].bar`: the value of the sub-property `"bar"` in the first element of
|
|
241
|
+
the array in the property `"foo"`.
|
|
242
|
+
|
|
243
|
+
This example merges the `"foo"` property of the parent with the child.
|
|
244
|
+
|
|
245
|
+
<!-- prettier-ignore-start -->
|
|
246
|
+
```javascript
|
|
247
|
+
// https://example.com/parent.json
|
|
248
|
+
// {
|
|
249
|
+
// "foo": { "bar": [1, 2], "baz": "a" },
|
|
250
|
+
// "qux": true
|
|
251
|
+
// }
|
|
252
|
+
|
|
253
|
+
const obj = { "$extends": "https://example.com/parent.json#foo" };
|
|
254
|
+
console.log(await JFather.extend(obj));
|
|
255
|
+
// { "bar": [1, 2], "baz": "a" }
|
|
256
|
+
```
|
|
257
|
+
<!-- prettier-ignore-end -->
|
|
232
258
|
|
|
233
259
|
### Override
|
|
234
260
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
If an object has arrays, the merge overwrites the parent's array with the
|
|
262
|
+
child's. With the properties `"$foo[42]"` and `"$foo[]"`, you can refine the
|
|
263
|
+
merge.
|
|
264
|
+
|
|
265
|
+
In this example, the array `"foo"` is not overwritten. The first value of the
|
|
266
|
+
`"foo"` array is merged with the value of the child's `"$foo[0]"` property. And
|
|
267
|
+
the second value of `"foo"` is copied into the result.
|
|
268
|
+
|
|
269
|
+
<!-- prettier-ignore-start -->
|
|
270
|
+
```javascript
|
|
271
|
+
const parent = { "foo": ["a", "Alpha"] };
|
|
272
|
+
const child = { "$foo[0]": "B" };
|
|
273
|
+
console.log(JFather.merge(parent, child));
|
|
274
|
+
// { "foo": ["B", "Alpha"] }
|
|
275
|
+
```
|
|
276
|
+
<!-- prettier-ignore-end -->
|
|
277
|
+
|
|
278
|
+
With `"$foo[]"`, the child's values are added to those of the parent. In the
|
|
279
|
+
example below, the values `"b"` and `"Beta"` are added to the array of the
|
|
280
|
+
`"foo"` property.
|
|
281
|
+
|
|
282
|
+
<!-- prettier-ignore-start -->
|
|
283
|
+
```javascript
|
|
284
|
+
const parent = { "foo": ["a", "Alpha"] };
|
|
285
|
+
const child = { "$foo[]": ["b", "Beta"] };
|
|
286
|
+
console.log(JFather.merge(parent, child));
|
|
287
|
+
// { "foo": ["a", "Alpha", "b", "Beta"] }
|
|
288
|
+
```
|
|
289
|
+
<!-- prettier-ignore-end -->
|
|
290
|
+
|
|
291
|
+
You can combine the two overloads to, for example:
|
|
292
|
+
|
|
293
|
+
- merge the first value of the parent's `"foo"` array with the value of the
|
|
294
|
+
child's `"$foo[0]"` property;
|
|
295
|
+
- add the values `"b"` and `"c"` to the array of the sub-property `"bar"`.
|
|
296
|
+
|
|
297
|
+
<!-- prettier-ignore-start -->
|
|
298
|
+
```javascript
|
|
299
|
+
const parent = {
|
|
266
300
|
"foo": [{
|
|
267
301
|
"bar": ["a"]
|
|
268
302
|
}]
|
|
269
|
-
}
|
|
270
|
-
|
|
303
|
+
};
|
|
304
|
+
const child = {
|
|
271
305
|
"$foo[0]": {
|
|
272
306
|
"$bar[]": ["b", "c"]
|
|
273
307
|
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
<!--
|
|
308
|
+
};
|
|
309
|
+
console.log(JFather.merge(parent, child));
|
|
310
|
+
// {
|
|
311
|
+
// "foo": [{
|
|
312
|
+
// "bar": ["a", "b", "c"]
|
|
313
|
+
// }]
|
|
314
|
+
// }
|
|
315
|
+
```
|
|
316
|
+
<!-- prettier-ignore-end -->
|
|
317
|
+
|
|
318
|
+
If the child overloads a property that does not exist in the parent, the
|
|
319
|
+
overload is ignored. The overload is also ignored if the parent object is not an
|
|
320
|
+
array. In the following example, the child has two overloads which are ignored:
|
|
321
|
+
the overload on the property `"bar"` which is not an array, and the overload on
|
|
322
|
+
`"baz"` which does not exist in the parent.
|
|
323
|
+
|
|
324
|
+
<!-- prettier-ignore-start -->
|
|
325
|
+
```javascript
|
|
326
|
+
const parent = { "foo": ["a", "A"], "bar": 42 };
|
|
327
|
+
const child = { "$bar[0]": 3.14, "$baz[]": ["beta"] };
|
|
328
|
+
console.log(JFather.merge(parent, child));
|
|
329
|
+
// { "foo": ["a", "A"], "bar": 42 }
|
|
330
|
+
```
|
|
331
|
+
<!-- prettier-ignore-end -->
|
|
283
332
|
|
|
284
333
|
## API
|
|
285
334
|
|
|
286
|
-
- [`merge()`](#
|
|
287
|
-
- [`extend()`](#
|
|
288
|
-
- [`load()`](#
|
|
289
|
-
- [`parse()`](#
|
|
335
|
+
- [`JFather.merge(parent, child)`](#jfathermergeparent-child)
|
|
336
|
+
- [`JFather.extend(obj, [options])`](#jfatherextendobj-options)
|
|
337
|
+
- [`JFather.load(url, [options])`](#jfatherloadurl-options)
|
|
338
|
+
- [`JFather.parse(text, [options])`](#jfatherparsetext-options)
|
|
290
339
|
|
|
291
|
-
### `merge()`
|
|
340
|
+
### `JFather.merge(parent, child)`
|
|
292
341
|
|
|
293
342
|
Merge and override `parent` with `child`.
|
|
294
343
|
|
|
295
|
-
```javascript
|
|
296
|
-
JFather.merge(parent, child);
|
|
297
|
-
```
|
|
298
|
-
|
|
299
344
|
- Parameters:
|
|
300
|
-
- `parent
|
|
301
|
-
- `child
|
|
302
|
-
- Returns: The merged object.
|
|
345
|
+
- `parent` [`<any>`][mdn-any] The parent object.
|
|
346
|
+
- `child` [`<any>`][mdn-any] The child object.
|
|
347
|
+
- Returns: [`<any>`][mdn-any] The merged object.
|
|
303
348
|
|
|
304
|
-
### `extend()`
|
|
349
|
+
### `JFather.extend(obj, [options])`
|
|
305
350
|
|
|
306
351
|
Extend `obj`, merge and override.
|
|
307
352
|
|
|
308
|
-
```javascript
|
|
309
|
-
JFather.extend(obj, [options]);
|
|
310
|
-
```
|
|
311
|
-
|
|
312
353
|
- Parameter:
|
|
313
|
-
- `obj
|
|
314
|
-
- `options
|
|
315
|
-
- `request
|
|
316
|
-
the object is got with
|
|
317
|
-
[`
|
|
318
|
-
|
|
319
|
-
- Returns: A promise with the extended object.
|
|
354
|
+
- `obj` [`<any>`][mdn-any] The object with any `$extends` properties.
|
|
355
|
+
- `options` [`<Object>`][mdn-object]
|
|
356
|
+
- `request` [`<Function>`][mdn-function] The function for getting a JSON
|
|
357
|
+
object remotely. By default, the object is got with [`fetch()`][mdn-fetch]
|
|
358
|
+
and [`Response.json()`][mdn-response-json].
|
|
359
|
+
- Returns: [`<Promise>`][mdn-promise] A promise with the extended object.
|
|
320
360
|
|
|
321
|
-
### `load()`
|
|
361
|
+
### `JFather.load(url, [options])`
|
|
322
362
|
|
|
323
|
-
Load from
|
|
324
|
-
|
|
325
|
-
```javascript
|
|
326
|
-
JFather.load(url, [options]);
|
|
327
|
-
```
|
|
363
|
+
Load from an `url`, extend, merge and override.
|
|
328
364
|
|
|
329
365
|
- Parameter:
|
|
330
|
-
- `url
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
[`fetch()`]
|
|
335
|
-
[`Response.json()`]
|
|
336
|
-
- Returns: A promise with the loaded object.
|
|
366
|
+
- `url` [`<String>`][mdn-string] | [`<URL>`][mdn-url] The string containing
|
|
367
|
+
the URL of a JSON file.
|
|
368
|
+
- `options` [`<Object>`][mdn-object]
|
|
369
|
+
- `request` [`<Function>`][mdn-function] The function for getting a JSON
|
|
370
|
+
object remotely. By default, the object is got with [`fetch()`][mdn-fetch]
|
|
371
|
+
and [`Response.json()`][mdn-response-json].
|
|
372
|
+
- Returns: [`<Promise>`][mdn-promise] A promise with the loaded object.
|
|
337
373
|
|
|
338
|
-
### `parse()`
|
|
374
|
+
### `JFather.parse(text, [options])`
|
|
339
375
|
|
|
340
376
|
Parse a `text`, extend, merge and override.
|
|
341
377
|
|
|
342
|
-
```javascript
|
|
343
|
-
JFather.parse(text, [options]);
|
|
344
|
-
```
|
|
345
|
-
|
|
346
378
|
- Parameter:
|
|
347
|
-
- `text
|
|
348
|
-
- `options
|
|
349
|
-
- `request
|
|
350
|
-
the object is got with
|
|
351
|
-
[`
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
[
|
|
356
|
-
|
|
357
|
-
[
|
|
358
|
-
|
|
379
|
+
- `text` [`<String>`][mdn-string] The string containing a JSON object.
|
|
380
|
+
- `options` [`<Object>`][mdn-object]
|
|
381
|
+
- `request` [`<Function>`][mdn-function] The function for getting a JSON
|
|
382
|
+
object remotely. By default, the object is got with [`fetch()`][mdn-fetch]
|
|
383
|
+
and [`Response.json()`][mdn-response-json].
|
|
384
|
+
- Returns: [`<Promise>`][mdn-promise] A promise with the parsed object.
|
|
385
|
+
|
|
386
|
+
[mdn-any]: https://developer.mozilla.org/Web/JavaScript/Data_structures
|
|
387
|
+
[mdn-function]:
|
|
388
|
+
https://developer.mozilla.org/JavaScript/Reference/Global_Objects/Function
|
|
389
|
+
[mdn-object]:
|
|
390
|
+
https://developer.mozilla.org/JavaScript/Reference/Global_Objects/Object
|
|
391
|
+
[mdn-promise]:
|
|
392
|
+
https://developer.mozilla.org/JavaScript/Reference/Global_Objects/Promise
|
|
393
|
+
[mdn-string]:
|
|
394
|
+
https://developer.mozilla.org/JavaScript/Reference/Global_Objects/String
|
|
395
|
+
[mdn-fetch]: https://developer.mozilla.org/Web/API/fetch
|
|
396
|
+
[mdn-response-json]: https://developer.mozilla.org/Web/API/Response/json
|
|
397
|
+
[mdn-url]: https://developer.mozilla.org/Web/API/URL
|
|
398
|
+
[img-npm]:
|
|
399
|
+
https://img.shields.io/npm/dm/jfather?label=npm&logo=npm&logoColor=whitesmoke
|
|
400
|
+
[img-build]:
|
|
401
|
+
https://img.shields.io/github/actions/workflow/status/regseb/jfather/ci.yml?branch=main&logo=github&logoColor=whitesmoke
|
|
402
|
+
[img-coverage]:
|
|
403
|
+
https://img.shields.io/endpoint?label=coverage&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fregseb%2Fjfather%2Fmain
|
|
404
|
+
[img-semver]:
|
|
405
|
+
https://img.shields.io/badge/semver-2.0.0-blue?logo=semver&logoColor=whitesmoke
|
|
359
406
|
[link-npm]: https://www.npmjs.com/package/jfather
|
|
360
|
-
[link-build]:
|
|
361
|
-
|
|
407
|
+
[link-build]:
|
|
408
|
+
https://github.com/regseb/jfather/actions/workflows/ci.yml?query=branch%3Amain
|
|
409
|
+
[link-coverage]:
|
|
410
|
+
https://dashboard.stryker-mutator.io/reports/github.com/regseb/jfather/main
|
|
362
411
|
[link-semver]: https://semver.org/spec/v2.0.0.html "Semantic Versioning 2.0.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jfather",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "JSON with merge, extend and override.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jfather",
|
|
@@ -35,50 +35,59 @@
|
|
|
35
35
|
},
|
|
36
36
|
"main": "./src/index.js",
|
|
37
37
|
"types": "./types/index.d.ts",
|
|
38
|
-
"repository":
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/regseb/jfather.git"
|
|
41
|
+
},
|
|
39
42
|
"type": "module",
|
|
40
43
|
"scripts": {
|
|
44
|
+
"prepare": "tsc --project .tsconfig_types.json",
|
|
41
45
|
"lint": "metalint",
|
|
42
46
|
"lint:fix": "metalint --fix",
|
|
43
47
|
"lint:types": "tsc --project .tsconfig_lint.json",
|
|
44
48
|
"test": "npm run test:coverage",
|
|
45
|
-
"test:unit": "
|
|
49
|
+
"test:unit": "npm run test:unit:node",
|
|
50
|
+
"test:unit:node": "node --test --import ./test/polyfills/node.js 'test/unit/**/*.test.js'",
|
|
51
|
+
"test:unit:bun": "bun test --preload ./test/polyfills/bun.js test/unit/",
|
|
46
52
|
"test:coverage": "stryker run",
|
|
47
53
|
"jsdocs": "typedoc --tsconfig .tsconfig_jsdocs.json",
|
|
48
|
-
"prepare": "tsc --project .tsconfig_types.json",
|
|
49
54
|
"clean": "node .script/clean.js"
|
|
50
55
|
},
|
|
51
56
|
"devDependencies": {
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"
|
|
60
|
-
"
|
|
57
|
+
"@biomejs/js-api": "4.0.0",
|
|
58
|
+
"@biomejs/wasm-nodejs": "2.3.11",
|
|
59
|
+
"@prantlf/jsonlint": "17.0.0",
|
|
60
|
+
"@prettier/plugin-xml": "3.4.2",
|
|
61
|
+
"@secretlint/secretlint-rule-github": "11.2.5",
|
|
62
|
+
"@secretlint/secretlint-rule-npm": "11.2.5",
|
|
63
|
+
"@stryker-mutator/core": "9.4.0",
|
|
64
|
+
"@stryker-mutator/tap-runner": "9.4.0",
|
|
65
|
+
"@types/bun": "1.3.5",
|
|
66
|
+
"@types/node": "25.0.3",
|
|
67
|
+
"eslint": "9.39.2",
|
|
68
|
+
"eslint-plugin-array-func": "5.1.0",
|
|
61
69
|
"eslint-plugin-eslint-comments": "3.2.0",
|
|
62
|
-
"eslint-plugin-import": "2.
|
|
63
|
-
"eslint-plugin-jsdoc": "
|
|
64
|
-
"eslint-plugin-mocha": "
|
|
65
|
-
"eslint-plugin-n": "17.
|
|
66
|
-
"eslint-plugin-no-unsanitized": "4.
|
|
67
|
-
"eslint-plugin-promise": "
|
|
68
|
-
"eslint-plugin-regexp": "2.
|
|
69
|
-
"eslint-plugin-unicorn": "
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
70
|
+
"eslint-plugin-import": "2.32.0",
|
|
71
|
+
"eslint-plugin-jsdoc": "61.5.0",
|
|
72
|
+
"eslint-plugin-mocha": "11.2.0",
|
|
73
|
+
"eslint-plugin-n": "17.23.1",
|
|
74
|
+
"eslint-plugin-no-unsanitized": "4.1.4",
|
|
75
|
+
"eslint-plugin-promise": "7.2.1",
|
|
76
|
+
"eslint-plugin-regexp": "2.10.0",
|
|
77
|
+
"eslint-plugin-unicorn": "62.0.0",
|
|
78
|
+
"globals": "17.0.0",
|
|
79
|
+
"jsr": "0.13.5",
|
|
80
|
+
"markdownlint": "0.40.0",
|
|
81
|
+
"metalint": "0.21.2",
|
|
82
|
+
"npm-package-json-lint": "9.1.0",
|
|
83
|
+
"prettier": "3.7.4",
|
|
84
|
+
"publint": "0.3.16",
|
|
85
|
+
"secretlint": "11.2.5",
|
|
86
|
+
"typedoc": "0.28.15",
|
|
87
|
+
"typescript": "5.9.3",
|
|
79
88
|
"yaml-lint": "1.7.0"
|
|
80
89
|
},
|
|
81
90
|
"engines": {
|
|
82
|
-
"node": ">=20.
|
|
91
|
+
"node": ">=20.18.0"
|
|
83
92
|
}
|
|
84
93
|
}
|
package/src/index.js
CHANGED
package/src/jfather.js
CHANGED
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
* @typedef {Object} Options
|
|
11
11
|
* @prop {Function} [request] La fonction pour récupérer un objet JSON à
|
|
12
12
|
* distance. Par défaut, l'objet est récupéré avec
|
|
13
|
-
*
|
|
14
|
-
* <code>Response.prototype.json()</code>
|
|
13
|
+
* `fetch()` et `Response.json()`.
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -22,7 +21,7 @@
|
|
|
22
21
|
* @param {Function} fn La fonction appliquée sur tous les objets.
|
|
23
22
|
* @returns {any} Le retour de la fonction.
|
|
24
23
|
*/
|
|
25
|
-
export const walk =
|
|
24
|
+
export const walk = (obj, fn) => {
|
|
26
25
|
if (Object === obj?.constructor) {
|
|
27
26
|
return fn(
|
|
28
27
|
Object.fromEntries(
|
|
@@ -46,7 +45,7 @@ export const walk = function (obj, fn) {
|
|
|
46
45
|
* @param {Function} fn La fonction asynchrone appliquée sur tous les objets.
|
|
47
46
|
* @returns {Promise<any>} Une promesse contenant le retour de la fonction.
|
|
48
47
|
*/
|
|
49
|
-
export const walkAsync = async
|
|
48
|
+
export const walkAsync = async (obj, fn) => {
|
|
50
49
|
if (Object === obj?.constructor) {
|
|
51
50
|
return await fn(
|
|
52
51
|
Object.fromEntries(
|
|
@@ -73,7 +72,7 @@ export const walkAsync = async function (obj, fn) {
|
|
|
73
72
|
* @param {any} obj Une variable quelconque.
|
|
74
73
|
* @returns {any} Le clone de la variable d'entrée.
|
|
75
74
|
*/
|
|
76
|
-
export const clone =
|
|
75
|
+
export const clone = (obj) => {
|
|
77
76
|
return walk(obj, (/** @type {any} */ v) => v);
|
|
78
77
|
};
|
|
79
78
|
|
|
@@ -85,16 +84,16 @@ export const clone = function (obj) {
|
|
|
85
84
|
* @returns {any} L'élément extrait.
|
|
86
85
|
* @throws {TypeError} Si le chemin est invalide.
|
|
87
86
|
*/
|
|
88
|
-
export const query =
|
|
87
|
+
export const query = (obj, chain) => {
|
|
89
88
|
if ("" === chain) {
|
|
90
89
|
return obj;
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
const re = /^\.(?<prop>\w+)|^\[(?<index>\d+)\]/
|
|
92
|
+
const re = /^\.(?<prop>\w+)|^\[(?<index>\d+)\]/v;
|
|
94
93
|
const sub = {
|
|
95
94
|
obj,
|
|
96
95
|
// Préfixer le chemin avec un point si nécessaire.
|
|
97
|
-
chain: /^[
|
|
96
|
+
chain: /^[.\[]/v.test(chain) ? chain : `.${chain}`,
|
|
98
97
|
};
|
|
99
98
|
while (0 !== sub.chain.length) {
|
|
100
99
|
const result = re.exec(sub.chain);
|
|
@@ -118,8 +117,12 @@ export const query = function (obj, chain) {
|
|
|
118
117
|
* @param {any} child L'objet enfant.
|
|
119
118
|
* @returns {any} La fusion des deux objets.
|
|
120
119
|
*/
|
|
121
|
-
export const merge =
|
|
122
|
-
if (
|
|
120
|
+
export const merge = (parent, child) => {
|
|
121
|
+
if (
|
|
122
|
+
child === parent ||
|
|
123
|
+
Object !== parent?.constructor ||
|
|
124
|
+
Object !== child?.constructor
|
|
125
|
+
) {
|
|
123
126
|
return clone(child);
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -149,8 +152,8 @@ export const merge = function (parent, child) {
|
|
|
149
152
|
// surcharges d'éléments.
|
|
150
153
|
if (Array.isArray(overridden[key])) {
|
|
151
154
|
const overelemRegex = new RegExp(
|
|
152
|
-
|
|
153
|
-
"
|
|
155
|
+
String.raw`^\$${key}\[(?<index>\d*)\]$`,
|
|
156
|
+
"v",
|
|
154
157
|
);
|
|
155
158
|
const overelems = Object.entries(child)
|
|
156
159
|
.map(([k, v]) => [overelemRegex.exec(k)?.groups?.index, v])
|
|
@@ -171,14 +174,14 @@ export const merge = function (parent, child) {
|
|
|
171
174
|
};
|
|
172
175
|
|
|
173
176
|
/**
|
|
174
|
-
* Étendre un objet JSON en utilisant
|
|
177
|
+
* Étendre un objet JSON en utilisant la propriété `"$extends"`.
|
|
175
178
|
*
|
|
176
179
|
* @param {Record<string, any>} obj L'objet qui sera étendu.
|
|
177
180
|
* @param {Options} [options] Les options.
|
|
178
181
|
* @returns {Promise<Record<string, any>>} Une promesse contenant l'objet
|
|
179
182
|
* étendu.
|
|
180
183
|
*/
|
|
181
|
-
export const inherit = async
|
|
184
|
+
export const inherit = async (obj, options) => {
|
|
182
185
|
if (undefined === obj.$extends) {
|
|
183
186
|
return obj;
|
|
184
187
|
}
|
|
@@ -194,18 +197,18 @@ export const inherit = async function (obj, options) {
|
|
|
194
197
|
* @param {Options} [options] Les options.
|
|
195
198
|
* @returns {Promise<any>} Une promesse contenant l'objet étendu.
|
|
196
199
|
*/
|
|
197
|
-
export const extend =
|
|
200
|
+
export const extend = (obj, options) => {
|
|
198
201
|
return walkAsync(obj, (/** @type {any} */ v) => inherit(v, options));
|
|
199
202
|
};
|
|
200
203
|
|
|
201
204
|
/**
|
|
202
205
|
* Charge un objet JSON depuis une URL.
|
|
203
206
|
*
|
|
204
|
-
* @param {string}
|
|
205
|
-
* @param {Options}
|
|
207
|
+
* @param {string|URL} url L'URL du fichier JSON.
|
|
208
|
+
* @param {Options} [options] Les options.
|
|
206
209
|
* @returns {Promise<any>} Une promesse contenant l'objet.
|
|
207
210
|
*/
|
|
208
|
-
export const load = async
|
|
211
|
+
export const load = async (url, options) => {
|
|
209
212
|
let json;
|
|
210
213
|
if (undefined === options?.request) {
|
|
211
214
|
const response = await fetch(url);
|
|
@@ -224,6 +227,6 @@ export const load = async function (url, options) {
|
|
|
224
227
|
* @param {Options} [options] Les options.
|
|
225
228
|
* @returns {Promise<any>} L'objet.
|
|
226
229
|
*/
|
|
227
|
-
export const parse =
|
|
230
|
+
export const parse = (text, options) => {
|
|
228
231
|
return extend(JSON.parse(text), options);
|
|
229
232
|
};
|
package/types/index.d.ts
CHANGED
package/types/jfather.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export function query(obj: Record<string, any>, chain: string): any;
|
|
|
5
5
|
export function merge(parent: any, child: any): any;
|
|
6
6
|
export function inherit(obj: Record<string, any>, options?: Options): Promise<Record<string, any>>;
|
|
7
7
|
export function extend(obj: any, options?: Options): Promise<any>;
|
|
8
|
-
export function load(url: string, options?: Options): Promise<any>;
|
|
8
|
+
export function load(url: string | URL, options?: Options): Promise<any>;
|
|
9
9
|
export function parse(text: string, options?: Options): Promise<any>;
|
|
10
10
|
/**
|
|
11
11
|
* Les options des fonctions de JFather.
|
|
@@ -14,8 +14,7 @@ export type Options = {
|
|
|
14
14
|
/**
|
|
15
15
|
* La fonction pour récupérer un objet JSON à
|
|
16
16
|
* distance. Par défaut, l'objet est récupéré avec
|
|
17
|
-
*
|
|
18
|
-
* <code>Response.prototype.json()</code>
|
|
17
|
+
* `fetch()` et `Response.json()`.
|
|
19
18
|
*/
|
|
20
19
|
request?: Function;
|
|
21
20
|
};
|