@fgv/ts-json-base 3.0.1-alpha.5 → 4.0.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/CHANGELOG.json CHANGED
@@ -1,6 +1,24 @@
1
1
  {
2
2
  "name": "@fgv/ts-json-base",
3
3
  "entries": [
4
+ {
5
+ "version": "4.0.0",
6
+ "tag": "@fgv/ts-json-base_v4.0.0",
7
+ "date": "Tue, 14 May 2024 03:09:27 GMT",
8
+ "comments": {
9
+ "none": [
10
+ {
11
+ "comment": "clean up and renaming in JSON file helpers"
12
+ },
13
+ {
14
+ "comment": "update generated api docs"
15
+ },
16
+ {
17
+ "comment": "generalize fs helper to enable yaml"
18
+ }
19
+ ]
20
+ }
21
+ },
4
22
  {
5
23
  "version": "3.0.0",
6
24
  "tag": "@fgv/ts-json-base_v3.0.0",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Change Log - @fgv/ts-json-base
2
2
 
3
- This log was last generated on Mon, 22 Jan 2024 07:00:18 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 14 May 2024 03:09:27 GMT and should not be manually modified.
4
+
5
+ ## 4.0.0
6
+ Tue, 14 May 2024 03:09:27 GMT
7
+
8
+ ### Updates
9
+
10
+ - clean up and renaming in JSON file helpers
11
+ - update generated api docs
12
+ - generalize fs helper to enable yaml
4
13
 
5
14
  ## 3.0.0
6
15
  Mon, 22 Jan 2024 07:00:18 GMT
package/README.md CHANGED
@@ -14,24 +14,6 @@ Assorted JSON-related typescript utilities that I'm tired of copying from projec
14
14
  - [Installation](#installation)
15
15
  - [Overview](#overview)
16
16
  - [Type-Safe JSON](#type-safe-json)
17
- - [Templated JSON](#templated-json)
18
- - [Multivalue Property Expansion](#multivalue-property-expansion)
19
- - [Conditional JSON](#conditional-json)
20
- - [Conditional Match Properties](#conditional-match-properties)
21
- - [Defined Condition Properties](#defined-condition-properties)
22
- - [Default Condition Properties](#default-condition-properties)
23
- - [Flattened Unconditional Blocks](#flattened-unconditional-blocks)
24
- - [Comments for Uniqueness](#comments-for-uniqueness)
25
- - [Templating with Conditional JSON](#templating-with-conditional-json)
26
- - [API](#api)
27
- - [JsonEditor class](#jsoneditor-class)
28
- - [mergeObjectInPlace method](#mergeobjectinplace-method)
29
- - [mergeObjectsInPlace method](#mergeobjectsinplace-method)
30
- - [clone method](#clone-method)
31
- - [Converters](#converters)
32
- - [Simple JSON Converter](#simple-json-converter)
33
- - [Templated JSON Converter](#templated-json-converter)
34
- - [Conditional JSON Converter](#conditional-json-converter)
35
17
  ## Installation
36
18
 
37
19
  With npm:
@@ -50,406 +32,3 @@ type JsonValue = JsonPrimitive | JsonObject | JsonArray;
50
32
  interface JsonArray extends Array<JsonValue> { }
51
33
  ```
52
34
 
53
- ### Templated JSON
54
- *Templated JSON* is type-safe JSON, with [mustache](https://www.npmjs.com/package/mustache) template conversions applied to any string properties or keys using a supplied context.
55
- ```ts
56
- const src = {
57
- '{{prop}}': '{{value}}',
58
- literalValue: 'literal',
59
- };
60
-
61
- const result = JsonConverters.templatedJson({ prop: 'someProp', value: 'some value' }).convert(src);
62
- // result.value is {
63
- // someProp: 'some value',
64
- // litealValue: 'literal',
65
- // }
66
- ```
67
-
68
- #### Multivalue Property Expansion
69
- In a templated JSON object, a key of the form ```*name=value1,value2...``` or ```"[[name]]=value1,value2,...``` is expanded to multiple values, one per item in the comma-separated list that follows the equals sign. The individual values are generated by resolving the property value with a context that includes a variable with the name specified and each of the values in the comma separated list, in turn. For ```*``` expansion the result is a property named for the variable with an array of all values. For ```[[``` expansion, the result is one property per value, where the property name matches the input value. For example:
70
- ```ts
71
- // with context:
72
- const context = {
73
- properties: ['first', 'second', 'third'],
74
- };
75
-
76
- // templated conversion of:
77
- const src = {
78
- '*prop={{properties}}': {
79
- '{{prop}}Prop': '{{prop}} value',
80
- },
81
- '[[prop]]={{properties}}': {
82
- '{{prop}}Prop': '{{prop}} value',
83
- },
84
- };
85
-
86
- // yields
87
- const expected = {
88
- first: {
89
- firstProp: 'first value',
90
- },
91
- second: {
92
- secondProp: 'second value',
93
- },
94
- third: {
95
- thirdProp: 'third value',
96
- },
97
- prop: ['first value', 'second value', 'third value'],
98
- };
99
- ```
100
-
101
- The converter options for templated JSON allow for an override of the function that derives the context for each of the children, so it is possible to write a custom derivation function which sets different or additional values based on the
102
- value passed in.
103
-
104
- ### Conditional JSON
105
-
106
- *Conditional JSON* is *templated JSON*, but property names beginning with '?' reperesent conditional properties.
107
-
108
- The value of any conditional property must be a JSON object. If the condition is satisfied, (a deep copy of) the children of the conditional property value are merged into the parent object. If the condition is not satisfied, the body is ignored.
109
-
110
- #### Conditional Match Properties
111
- Conditional match properties are identified by names with one of these forms:
112
- ```ts
113
- '?value1=value2'
114
- '?value1>=value2'
115
- '?value1<=value2'
116
- '?value1!=value2'
117
- '?value1>value2'
118
- '?value1<value2'
119
- ```
120
- Where *value1* and *value2* are strings that do not include any of the valid operators. The condition is satisfied if *value2* and *value2* match according to the operator. For example:
121
- ```ts
122
- {
123
- '?someValue=someValue': {
124
- conditional1: 'conditional value 1',
125
- },
126
- '?someValue=someOtherValue': {
127
- conditional2: 'conditional value 2',
128
- },
129
- '?3>1': {
130
- conditional3: '3 is greater than 1',
131
- },
132
- '?3<1': {
133
- conditional4: 'this is wrong',
134
- },
135
- unconditional: true,
136
- }
137
- // yields
138
- {
139
- conditional1: 'conditional value 1',
140
- conditional3: '3 is greater than 1',
141
- unconditional: true,
142
- }
143
- ```
144
-
145
- #### Defined Condition Properties
146
- Defined condition properties are identified by names of the form:
147
- ```ts
148
- '?value'
149
- ```
150
- Where *value* is any string, including the empty string. The condition is satisfied if *value* is not-empty or whitespace. For example:
151
- ```ts
152
- {
153
- '?someValue': {
154
- conditional: 'conditional value',
155
- },
156
- unconditional: 'unconditional value',
157
- }
158
- // yields
159
- {
160
- conditional: 'condtional value',
161
- unconditional: 'unconditional value',
162
- }
163
- ```
164
- but
165
- ```ts
166
- {
167
- '?': {
168
- conditional: 'conditional value',
169
- },
170
- unconditional: 'unconditional value',
171
- }
172
- // yields
173
- {
174
- unconditional: 'unconditional value',
175
- }
176
- ```
177
-
178
- #### Default Condition Properties
179
- The special conditional property *'?default'* is satisfied if none of the immediately preceding conditional properties match, otherwise it is omitted. For example:
180
- ```ts
181
- {
182
- '?someValue=someOtherValue': {
183
- conditional1: 'conditional value 1',
184
- },
185
- '?default': {
186
- conditional1: 'default conditional value',
187
- }
188
- }
189
- // yields
190
- {
191
- conditional1: 'default conditional value',
192
- }
193
- ```
194
- but
195
- ```ts
196
- {
197
- '?someValue=someValue': {
198
- conditional1: 'conditional value 1',
199
- },
200
- '?default': {
201
- conditional1: 'default conditional value',
202
- }
203
- }
204
- // yields
205
- {
206
- conditional1: 'conditional value 1',
207
- }
208
- ```
209
-
210
- #### Flattened Unconditional Blocks
211
- A default value is ignored if any conditional property in the same object was matched. To allow grouping of related conditional values with defaults, the conditional processor also supports
212
- unconditional properties with the '!' prefix. Any unconditional object properties are flattened and omitted. For example:
213
- ```ts
214
- {
215
- '!block1': {
216
- '?val1=val2': {
217
- gotVal1: 'match',
218
- },
219
- '?default': {
220
- gotVal1: 'default',
221
- }
222
- },
223
- '!block2': {
224
- '?val2=val3': {
225
- gotVal2: 'match',
226
- },
227
- '?default': {
228
- gotVal2: 'default',
229
- }
230
- },
231
- }
232
- // yields
233
- {
234
- gotVal1: 'default',
235
- gotVal2: 'default',
236
- }
237
- ```
238
-
239
- #### Comments for Uniqueness
240
- In any conditional property name, anything that follows the first '#' character is ignored. This makes it possible to include multiple conditions that match the same value. For example:
241
- ```ts
242
- {
243
- '?this=this': {
244
- conditional: 'conditional 1',
245
- },
246
- unconditional: 'unconditional',
247
- '?this=this': {
248
- conditional: 'conditional 2'
249
- }
250
- }
251
- ```
252
- is not valid JSON, because two properties have the same name, but:
253
- ```ts
254
- {
255
- '?this=this#1': {
256
- conditional: 'conditional 1',
257
- },
258
- unconditional: 'unconditional',
259
- '?this=this#2': {
260
- conditional: 'conditional 2'
261
- }
262
- }
263
- // is valid, and yields:
264
- {
265
- unconditional: 'unconditional',
266
- conditional: 'conditional 2',
267
- }
268
- ```
269
-
270
- ### Templating with Conditional JSON
271
- Combined with [mustache](https://www.npmjs.com/package/mustache) templating, this conditional syntax allows simple and powerful generation or consumption of conditional JSON files. For example, consider:
272
- ```ts
273
- {
274
- userName: '{{user}}',
275
- password: '{{pw}}',
276
- '?{{userType}}=admin': {
277
- rights: '...' // rights for admin
278
- },
279
- '?{{userType}}=bot': {
280
- rights: '...' // rights for bot
281
- }
282
- '?{{default}}': {
283
- rights: '...' // rights for normal user
284
- },
285
- '?{{externalId}}': {
286
- externalId: '{{externalId}}',
287
- }
288
- }
289
- ```
290
- Given the context:
291
- ```ts
292
- {
293
- user: 'fred',
294
- pw: 'freds password',
295
- userType: 'admin',
296
- externalId: 'freds SSO credentials',
297
- }
298
- ```
299
- Our example yields:
300
- ```ts
301
- {
302
- userName: 'fred',
303
- password: 'freds password',
304
- rights: '...', // rights for admin
305
- externalId: 'freds SSO credentials',
306
- }
307
- ```
308
- But given the context:
309
- ```ts
310
- {
311
- user: 'r2d2',
312
- password: 'r2s pw',
313
- userType: 'bot',
314
- }
315
- ```
316
- We get:
317
- ```ts
318
- {
319
- userName: 'r2d2',
320
- password: 'r2s pw',
321
- rights: '...', // rights for bot
322
- }
323
- ```
324
-
325
- ## API
326
-
327
- ### JsonEditor class
328
- The *JsonEditor* can be used to edite JSON objects in place or to clone any JSON value,
329
- applying a default context and optional set of editor rules (e.g. for templating, conditional,
330
- multi-value or reference processing) to be applied.
331
-
332
- #### mergeObjectInPlace method
333
- The *mergeObjectInPlace* function takes a base object an object to be merged and updates the supplied base object with values from the merge object. For example:
334
- ```ts
335
- const base = {
336
- property1: 'value 1',
337
- property2: 'value 2',
338
- };
339
- const merge = {
340
- property2: 'value 2A',
341
- property3: 'value 3A',
342
- };
343
- const result = editor.mergeObjectInPlace(base, merge);
344
- // updates the base object and returns success with base object, which means
345
- // that both base and result.value have the shape:
346
- {
347
- property1: 'value 1',
348
- property2: 'value 2A',
349
- property3: 'value 3A',
350
- }
351
- ```
352
-
353
- #### mergeObjectsInPlace method
354
- The *mergeObjectsInPlace* function takes a base object and one or more objects to be merged, and updates the base object with values from each of the merge objects in the order supplied. for example:
355
- ```ts
356
- const base = {
357
- property1: 'value 1',
358
- property2: 'value 2',
359
- };
360
- const mergeA = {
361
- property2: 'value 2A',
362
- property3: 'value 3A',
363
- };
364
- const mergeB = {
365
- property3: 'value 3B',
366
- property4: 'value 4B',
367
- };
368
- const result = editor.mergeObjectsInPlace(base, mergeA, mergeB);
369
- // updates the base object and returns success with base object, which means
370
- // that both base and result.value have the shape:
371
- {
372
- property1: 'value 1',
373
- property2: 'value 2A',
374
- property3: 'value 3B',
375
- property4: 'value 4B',
376
- }
377
- ```
378
-
379
- #### clone method
380
- The *clone* method deep clones a supplied JSON value, applying all editor rules and
381
- a default or optionally supplied context.
382
-
383
- ### Converters
384
-
385
- A convenience set of [ts-utils *Converters*](https://github.com/DidjaRedo/ts-utils/blob/master/README.md) and generators for the most common JSON conversions.
386
-
387
- #### Simple JSON Converter
388
-
389
- Use the *json* converter to convert unknown to type-safe JSON. Fails if the value to be converted is not valid JSON.
390
- ```ts
391
- import * as JsonConverters from '@fgv/ts-json/converters';
392
-
393
- const result = JsonConverters.json.convert(someUnknown);
394
- if (result.isSuccess()) {
395
- // someUnknown was valid JSON
396
- // jsonResult.value is a JsonValue deep copy of someUnknown
397
- }
398
- else {
399
- // someUnknown was not valid JSON
400
- // jsonResult.message describes the error
401
- }
402
- ```
403
-
404
- #### Templated JSON Converter
405
-
406
- Use the *templatedJson* converter to convert unknown to type-safe JSON, applying [mustache](https://www.npmjs.com/package/mustache) template conversions to any string properties or keys using the supplied context.
407
- ```ts
408
- const src = {
409
- '{{prop}}': '{{value}}',
410
- literalValue: 'literal',
411
- };
412
-
413
- const result = JsonConverters.templatedJson({ prop: 'someProp', value: 'some value' }).convert(src);
414
- // result.value is {
415
- // someProp: 'some value',
416
- // litealValue: 'literal',
417
- // }
418
- ```
419
-
420
- #### Conditional JSON Converter
421
-
422
- Use the *conditionalJson* converter to convert unknown to type-safe JSON, applying [mustache](https://www.npmjs.com/package/mustache) template conversions to any string properties or keys using the supplied context *and* merging or omitting conditional properties as appropriate. For example:
423
- ```ts
424
- const config = {
425
- userName: '{{user}}',
426
- password: '{{pw}}',
427
- '?{{userType}}=admin': {
428
- rights: '...' // rights for admin
429
- },
430
- '?{{userType}}=bot': {
431
- rights: '...' // rights for bot
432
- }
433
- '?{{default}}': {
434
- rights: '...' // rights for normal user
435
- },
436
- '?{{externalId}}': {
437
- externalId: '{{externalId}}',
438
- }
439
- };
440
- const context = {
441
- user: 'fred',
442
- pw: 'freds password',
443
- userType: 'admin',
444
- externalId: 'freds SSO credentials',
445
- };
446
-
447
- const result = JsonConverters.conditionalJson(context).convert(config);
448
- // succeeds and yields
449
- {
450
- userName: 'fred',
451
- password: 'freds password',
452
- rights: '...', // rights for admin
453
- externalId: 'freds SSO credentials',
454
- }
455
- ```
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.39.4"
8
+ "packageVersion": "7.43.4"
9
9
  }
10
10
  ]
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-json-base",
3
- "version": "3.0.1-alpha.5",
3
+ "version": "4.0.0",
4
4
  "description": "Typescript types and basic functions for working with json",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-json-base.d.ts",
@@ -16,35 +16,33 @@
16
16
  "homepage": "https://github.com/ErikFortune/fgv/tree/main/libraries/ts-json-base#readme",
17
17
  "sideEffects": false,
18
18
  "devDependencies": {
19
- "@fgv/ts-utils": "3.0.1-alpha.5",
20
- "@fgv/ts-utils-jest": "3.0.1-alpha.5",
19
+ "@fgv/ts-utils": "4.0.0",
20
+ "@fgv/ts-utils-jest": "4.0.0",
21
21
  "@types/jest": "^29.5.12",
22
- "@types/mustache": "^4.2.5",
23
- "@types/node": "^20.11.16",
24
- "@typescript-eslint/eslint-plugin": "^6.20.0",
25
- "@typescript-eslint/parser": "^6.20.0",
26
- "eslint": "^8.56.0",
22
+ "@types/node": "^20.12.11",
23
+ "@typescript-eslint/eslint-plugin": "^7.9.0",
24
+ "@typescript-eslint/parser": "^7.9.0",
25
+ "eslint": "^8.57.0",
27
26
  "eslint-config-standard": "^17.1.0",
28
27
  "eslint-plugin-import": "^2.29.1",
29
28
  "eslint-plugin-node": "^11.1.0",
30
29
  "eslint-plugin-promise": "^6.1.1",
31
30
  "jest": "^29.7.0",
32
31
  "jest-extended": "^4.0.2",
33
- "mustache": "^4.2.0",
34
- "rimraf": "^5.0.5",
32
+ "rimraf": "^5.0.7",
35
33
  "ts-jest": "^29.1.2",
36
34
  "ts-node": "^10.9.2",
37
- "typescript": "^5.3.3",
35
+ "typescript": "^5.4.5",
38
36
  "eslint-plugin-n": "^16.6.2",
39
- "@rushstack/heft-node-rig": "~2.4.5",
40
- "@rushstack/heft": "~0.64.3",
37
+ "@rushstack/heft-node-rig": "~2.6.3",
38
+ "@rushstack/heft": "~0.66.6",
41
39
  "heft-jest": "~1.0.2",
42
40
  "@types/heft-jest": "1.0.6",
43
- "@microsoft/api-documenter": "^7.23.20"
41
+ "@microsoft/api-documenter": "^7.24.5",
42
+ "@fgv/ts-extras": "4.0.0"
44
43
  },
45
44
  "peerDependencies": {
46
- "@fgv/ts-utils": "3.0.1-alpha.5",
47
- "mustache": "^4.2.0"
45
+ "@fgv/ts-utils": "4.0.0"
48
46
  },
49
47
  "scripts": {
50
48
  "build": "heft test --clean",