@sleekcms/json-zen 1.4.0 → 1.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/README.md +9 -6
- package/package.json +1 -1
- package/src/index.ts +18 -3
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A compact, string-based schema syntax for validating and shaping JSON objects — with far less boilerplate than JSON Schema.
|
|
4
4
|
|
|
5
|
+
Try it live at **[json-zen.sleekcms.site](https://json-zen.sleekcms.site/)**.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -79,11 +81,12 @@ verify([1, 'x', 2, 'y'], '[n,s]'); // true — alternating number/string
|
|
|
79
81
|
|
|
80
82
|
### Optional fields (`?`)
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
For object properties, suffix the key with `?` to make it optional (TypeScript-style). For array elements, prefix the type with `?`. A missing or `null` value passes validation.
|
|
83
85
|
|
|
84
86
|
```js
|
|
85
|
-
verify({ a: 1 }, '{a:n, b
|
|
86
|
-
verify({ a: 1, b: null }, '{a:n, b
|
|
87
|
+
verify({ a: 1 }, '{a:n, b?:s}'); // true — b is missing but optional
|
|
88
|
+
verify({ a: 1, b: null }, '{a:n, b?:s}'); // true
|
|
89
|
+
verify([1, null, 3], '[?n]'); // true — array elements are optional
|
|
87
90
|
```
|
|
88
91
|
|
|
89
92
|
### Presence-only validation
|
|
@@ -198,12 +201,12 @@ shape({ a: {} }, '{a:{x:n, y:s}}');
|
|
|
198
201
|
|
|
199
202
|
| Option | Type | Description |
|
|
200
203
|
|-------------|-----------|--------------------------------------------------------------|
|
|
201
|
-
| `
|
|
204
|
+
| `fillNulls` | `boolean` | When `true`, fill optional (`?`) fields with defaults instead of `null` |
|
|
202
205
|
| _(key)_ | validator | Inline custom type |
|
|
203
206
|
|
|
204
207
|
```js
|
|
205
|
-
shape({}, '{a
|
|
206
|
-
shape({}, '{a
|
|
208
|
+
shape({}, '{a?:n}'); // { a: null }
|
|
209
|
+
shape({}, '{a?:n}', { fillNulls: true }); // { a: 0 }
|
|
207
210
|
```
|
|
208
211
|
|
|
209
212
|
---
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -82,6 +82,11 @@ export const typeShape = (schema: string): TypeShape => {
|
|
|
82
82
|
return sch.split(",").reduce((acc: { [key: string]: TypeShape }, name) => {
|
|
83
83
|
let [k, v] = splitOnce(name, ":");
|
|
84
84
|
if (k.match(RX.DEFAULTS)) k = default_strings[Number(k.slice(1))];
|
|
85
|
+
// TypeScript-style optional: key? instead of ?type
|
|
86
|
+
if (k.endsWith('?')) {
|
|
87
|
+
k = k.slice(0, -1);
|
|
88
|
+
v = '?' + v;
|
|
89
|
+
}
|
|
85
90
|
acc[k] = traverse(v);
|
|
86
91
|
return acc;
|
|
87
92
|
}, {});
|
|
@@ -136,14 +141,14 @@ export const toSchema = (json: unknown, options: ToSchemaOptions = {}): string =
|
|
|
136
141
|
};
|
|
137
142
|
|
|
138
143
|
export interface ShapeOptions {
|
|
139
|
-
|
|
144
|
+
fillNulls?: boolean;
|
|
140
145
|
[key: string]: unknown;
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
export const shape = <T = unknown>(json: unknown, schema: string, options: ShapeOptions = {}): T => {
|
|
144
149
|
const types = new ZenTypes(options);
|
|
145
150
|
|
|
146
|
-
options.
|
|
151
|
+
options.fillNulls = options.fillNulls || false;
|
|
147
152
|
let lookups: string[];
|
|
148
153
|
let default_strings: string[];
|
|
149
154
|
[schema, lookups, default_strings] = _flatten(schema);
|
|
@@ -177,7 +182,7 @@ export const shape = <T = unknown>(json: unknown, schema: string, options: Shape
|
|
|
177
182
|
// if lookup, validate further
|
|
178
183
|
if (schema.match(RX.LOOKUP)) return traverse({ value, schema: `${optional ? '?' : ''}${lookups[Number(schema)]}` });
|
|
179
184
|
|
|
180
|
-
if ((value === null || value === undefined) && optional && !options.
|
|
185
|
+
if ((value === null || value === undefined) && optional && !options.fillNulls) return null;
|
|
181
186
|
|
|
182
187
|
if (schema.match(RX.FLAT_SCALAR)) {
|
|
183
188
|
// if scalar
|
|
@@ -212,6 +217,11 @@ export const shape = <T = unknown>(json: unknown, schema: string, options: Shape
|
|
|
212
217
|
let [k, t, d] = name.split(":");
|
|
213
218
|
if (!t) t = "";
|
|
214
219
|
if (d) t += ":" + d;
|
|
220
|
+
// TypeScript-style optional: key? instead of ?type
|
|
221
|
+
if (k.endsWith('?')) {
|
|
222
|
+
k = k.slice(0, -1);
|
|
223
|
+
t = '?' + t;
|
|
224
|
+
}
|
|
215
225
|
if (k === "*") wildcard = t;
|
|
216
226
|
else acc[k] = traverse({ value: obj[k], schema: t });
|
|
217
227
|
return acc;
|
|
@@ -304,6 +314,11 @@ export const verify = (json: unknown, schema: string, options: VerifyOptions = {
|
|
|
304
314
|
const keys = schema.split(",").reduce((acc: Record<string, string>, name) => {
|
|
305
315
|
let [k, t] = name.split(":");
|
|
306
316
|
if (!t) t = "";
|
|
317
|
+
// TypeScript-style optional: key? instead of ?type
|
|
318
|
+
if (k.endsWith('?')) {
|
|
319
|
+
k = k.slice(0, -1);
|
|
320
|
+
t = '?' + t;
|
|
321
|
+
}
|
|
307
322
|
if (k === '*') wildcard = t;
|
|
308
323
|
else acc[k] = t;
|
|
309
324
|
return acc;
|