@fgv/ts-json-base 2.0.1
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 +21 -0
- package/README.md +455 -0
- package/dist/ts-json-base.d.ts +202 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +54 -0
- package/lib/index.js.map +1 -0
- package/lib/packlets/json/common.d.ts +85 -0
- package/lib/packlets/json/common.d.ts.map +1 -0
- package/lib/packlets/json/common.js +123 -0
- package/lib/packlets/json/common.js.map +1 -0
- package/lib/packlets/json/index.d.ts +2 -0
- package/lib/packlets/json/index.d.ts.map +1 -0
- package/lib/packlets/json/index.js +39 -0
- package/lib/packlets/json/index.js.map +1 -0
- package/lib/packlets/json-file/file.d.ts +83 -0
- package/lib/packlets/json-file/file.d.ts.map +1 -0
- package/lib/packlets/json-file/file.js +162 -0
- package/lib/packlets/json-file/file.js.map +1 -0
- package/lib/packlets/json-file/index.d.ts +2 -0
- package/lib/packlets/json-file/index.d.ts.map +1 -0
- package/lib/packlets/json-file/index.js +39 -0
- package/lib/packlets/json-file/index.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Erik Fortune
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>ts-json</h1>
|
|
3
|
+
Typescript Utilities for JSON
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<hr/>
|
|
7
|
+
|
|
8
|
+
## Summary
|
|
9
|
+
|
|
10
|
+
Assorted JSON-related typescript utilities that I'm tired of copying from project to project.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
- [Summary](#summary)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Overview](#overview)
|
|
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
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
With npm:
|
|
38
|
+
```sh
|
|
39
|
+
npm install ts-json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Overview
|
|
43
|
+
|
|
44
|
+
### Type-Safe JSON
|
|
45
|
+
A handful of types express valid JSON as typescript types:
|
|
46
|
+
```ts
|
|
47
|
+
type JsonPrimitive = boolean | number | string | null;
|
|
48
|
+
interface JsonObject { [key: string]: JsonValue }
|
|
49
|
+
type JsonValue = JsonPrimitive | JsonObject | JsonArray;
|
|
50
|
+
interface JsonArray extends Array<JsonValue> { }
|
|
51
|
+
```
|
|
52
|
+
|
|
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
|
+
```
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Converter } from '@fgv/ts-utils';
|
|
2
|
+
import { Result } from '@fgv/ts-utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Identifies whether some `unknown` value is a {@link JsonPrimitive | primitive},
|
|
6
|
+
* {@link JsonObject | object} or {@link JsonArray | array}. Fails for any value
|
|
7
|
+
* that cannot be converted to JSON (e.g. a function) _but_ this is a shallow test -
|
|
8
|
+
* it does not test the properties of an object or elements in an array.
|
|
9
|
+
* @param from - The `unknown` value to be tested
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export declare function classifyJsonValue(from: unknown): Result<JsonValueType>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reads all JSON files from a directory and apply a supplied converter.
|
|
16
|
+
* @param srcPath - The path of the folder to be read.
|
|
17
|
+
* @param options - {@link Files.IDirectoryConvertOptions | Options} to control
|
|
18
|
+
* conversion and filtering
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
declare function convertJsonDirectorySync<T>(srcPath: string, options: IDirectoryConvertOptions<T>): Result<IReadDirectoryItem<T>[]>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reads and converts all JSON files from a directory, returning a
|
|
25
|
+
* `Map<string, T>` indexed by file base name (i.e. minus the extension)
|
|
26
|
+
* with an optional name transformation applied if present.
|
|
27
|
+
* @param srcPath - The path of the folder to be read.
|
|
28
|
+
* @param options - {@link Files.IDirectoryToMapConvertOptions | Options} to control conversion,
|
|
29
|
+
* filtering and naming.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
declare function convertJsonDirectoryToMapSync<T, TC = unknown>(srcPath: string, options: IDirectoryToMapConvertOptions<T, TC>): Result<Map<string, T>>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Convenience function to read a JSON file and apply a supplied converter.
|
|
36
|
+
* @param srcPath - Path of the file to read.
|
|
37
|
+
* @param converter - `Converter` used to convert the file contents
|
|
38
|
+
* @returns `Success` with a result of type `<T>`, or `Failure`
|
|
39
|
+
* with a message if an error occurs.
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
declare function convertJsonFileSync<T>(srcPath: string, converter: Converter<T>): Result<T>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Options for directory conversion.
|
|
46
|
+
* TODO: add filtering, allowed and excluded.
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
declare interface IDirectoryConvertOptions<T, TC = unknown> {
|
|
50
|
+
/**
|
|
51
|
+
* The converter used to convert incoming JSON objects.
|
|
52
|
+
*/
|
|
53
|
+
converter: Converter<T, TC>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Options controlling conversion of a directory.
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
declare interface IDirectoryToMapConvertOptions<T, TC = unknown> extends IDirectoryConvertOptions<T, TC> {
|
|
61
|
+
transformName?: ItemNameTransformFunction<T>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Return value for one item in a directory conversion.
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
declare interface IReadDirectoryItem<T> {
|
|
69
|
+
/**
|
|
70
|
+
* Relative name of the file that was processed
|
|
71
|
+
*/
|
|
72
|
+
filename: string;
|
|
73
|
+
/**
|
|
74
|
+
* The payload of the file.
|
|
75
|
+
*/
|
|
76
|
+
item: T;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Test if an `unknown` is potentially a {@link JsonArray | JsonArray}.
|
|
81
|
+
* @param from - The `unknown` to be tested.
|
|
82
|
+
* @returns `true` if the supplied parameter is an array object,
|
|
83
|
+
* `false` otherwise.
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
export declare function isJsonArray(from: unknown): from is JsonArray;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Test if an `unknown` is potentially a {@link JsonObject | JsonObject}.
|
|
90
|
+
* @param from - The `unknown` to be tested.
|
|
91
|
+
* @returns `true` if the supplied parameter is a non-array, non-special object,
|
|
92
|
+
* `false` otherwise.
|
|
93
|
+
* @public
|
|
94
|
+
*/
|
|
95
|
+
export declare function isJsonObject(from: unknown): from is JsonObject;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Test if an `unknown` is a {@link JsonValue | JsonValue}.
|
|
99
|
+
* @param from - The `unknown` to be tested
|
|
100
|
+
* @returns `true` if the supplied parameter is a valid {@link JsonPrimitive | JsonPrimitive},
|
|
101
|
+
* `false` otherwise.
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export declare function isJsonPrimitive(from: unknown): from is JsonPrimitive;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Function to transform the name of a some entity, given an original name
|
|
108
|
+
* and the contents of the entity.
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
declare type ItemNameTransformFunction<T> = (name: string, item: T) => Result<string>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A {@link JsonArray | JsonArray} is an array containing only valid {@link JsonValue | JsonValues}.
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export declare interface JsonArray extends Array<JsonValue> {
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
declare namespace JsonFile {
|
|
121
|
+
export {
|
|
122
|
+
readJsonFileSync,
|
|
123
|
+
convertJsonFileSync,
|
|
124
|
+
convertJsonDirectorySync,
|
|
125
|
+
convertJsonDirectoryToMapSync,
|
|
126
|
+
writeJsonFileSync,
|
|
127
|
+
IDirectoryConvertOptions,
|
|
128
|
+
IReadDirectoryItem,
|
|
129
|
+
ItemNameTransformFunction,
|
|
130
|
+
IDirectoryToMapConvertOptions
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export { JsonFile }
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A {@link JsonObject | JsonObject} is a string-keyed object
|
|
137
|
+
* containing only valid {@link JsonValue | JSON values}.
|
|
138
|
+
* @public
|
|
139
|
+
*/
|
|
140
|
+
export declare interface JsonObject {
|
|
141
|
+
[key: string]: JsonValue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Primitive (terminal) values allowed in by JSON.
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
export declare type JsonPrimitive = boolean | number | string | null;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* A {@link JsonValue | JsonValue} is one of: a {@link JsonPrimitive | JsonPrimitive},
|
|
152
|
+
* a {@link JsonObject | JsonObject} or an {@link JsonArray | JsonArray}.
|
|
153
|
+
* @public
|
|
154
|
+
*/
|
|
155
|
+
export declare type JsonValue = JsonPrimitive | JsonObject | JsonArray;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Classes of {@link JsonValue | JsonValue}.
|
|
159
|
+
* @public
|
|
160
|
+
*/
|
|
161
|
+
export declare type JsonValueType = 'primitive' | 'object' | 'array';
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Picks a nested {@link JsonObject | JsonObject} from a supplied
|
|
165
|
+
* {@link JsonObject | JsonObject}.
|
|
166
|
+
* @param src - The {@link JsonObject | object} from which the field is
|
|
167
|
+
* to be picked.
|
|
168
|
+
* @param path - Dot-separated path of the member to be picked.
|
|
169
|
+
* @returns `Success` with the property if the path is valid and the value
|
|
170
|
+
* is an object. Returns `Failure` with details if an error occurs.
|
|
171
|
+
* @public
|
|
172
|
+
*/
|
|
173
|
+
export declare function pickJsonObject(src: JsonObject, path: string): Result<JsonObject>;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Picks a nested field from a supplied {@link JsonObject | JsonObject}.
|
|
177
|
+
* @param src - The {@link JsonObject | object} from which the field is to be picked.
|
|
178
|
+
* @param path - Dot-separated path of the member to be picked.
|
|
179
|
+
* @returns `Success` with the property if the path is valid, `Failure`
|
|
180
|
+
* with an error message otherwise.
|
|
181
|
+
* @public
|
|
182
|
+
*/
|
|
183
|
+
export declare function pickJsonValue(src: JsonObject, path: string): Result<JsonValue>;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Convenience function to read type-safe JSON from a file
|
|
187
|
+
* @param srcPath - Path of the file to read
|
|
188
|
+
* @returns `Success` with a {@link JsonValue | JsonValue} or `Failure`
|
|
189
|
+
* with a message if an error occurs.
|
|
190
|
+
* @public
|
|
191
|
+
*/
|
|
192
|
+
declare function readJsonFileSync(srcPath: string): Result<JsonValue>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Convenience function to write type-safe JSON to a file.
|
|
196
|
+
* @param srcPath - Path of the file to write.
|
|
197
|
+
* @param value - The {@link JsonValue | JsonValue} to be written.
|
|
198
|
+
* @public
|
|
199
|
+
*/
|
|
200
|
+
declare function writeJsonFileSync(srcPath: string, value: JsonValue): Result<boolean>;
|
|
201
|
+
|
|
202
|
+
export { }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.39.1"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AAEjD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|