Skip to content

Commit 28e2f81

Browse files
authored
Merge pull request #29 from jsonjoy-com/api-improvements
Api improvements
2 parents b74dbd3 + 2eb08ca commit 28e2f81

30 files changed

+1544
-99
lines changed

SPECIFICATION.md

Lines changed: 718 additions & 0 deletions
Large diffs are not rendered by default.

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ export * from './constants';
5252
export * from './schema';
5353
export * from './type';
5454
export * from './system';
55+
export * from './value';

src/random/generators.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,14 @@ export const num = (type: NumberType): number => {
6565
let min = Number.MIN_SAFE_INTEGER;
6666
let max = Number.MAX_SAFE_INTEGER;
6767
const schema = type.getSchema();
68-
if (schema.gt !== undefined) min = schema.gt;
69-
if (schema.gte !== undefined) min = schema.gte + 0.000000000000001;
70-
if (schema.lt !== undefined) max = schema.lt;
71-
if (schema.lte !== undefined) max = schema.lte - 0.000000000000001;
68+
const {lt, lte, gt, gte} = schema;
69+
if (gt !== undefined) min = gt;
70+
if (gte !== undefined)
71+
if (gte === lte) return gte;
72+
else min = gte + 0.000000000000001;
73+
if (lt !== undefined) max = lt;
74+
if (lte !== undefined) max = lte - 0.000000000000001;
75+
if (min >= max) return max;
7276
if (schema.format) {
7377
switch (schema.format) {
7478
case 'i8':

src/schema/SchemaBuilder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
FunctionSchema,
2020
FunctionStreamingSchema,
2121
TType,
22+
Narrow,
2223
} from '.';
2324

2425
export class SchemaBuilder {
@@ -127,7 +128,7 @@ export class SchemaBuilder {
127128
* ```
128129
*/
129130
public Const<V>(
130-
value: V,
131+
value: Narrow<V>,
131132
options?: Optional<ConstSchema<V>>,
132133
): ConstSchema<
133134
string extends V ? never : number extends V ? never : boolean extends V ? never : any[] extends V ? never : V

src/schema/__tests__/SchemaBuilder.spec.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {s} from '..';
1+
import {type ConstSchema, s} from '..';
22

33
describe('string', () => {
44
test('can create a string type', () => {
@@ -79,3 +79,14 @@ describe('or', () => {
7979
});
8080
});
8181
});
82+
83+
describe('const', () => {
84+
test('can create an "const" type', () => {
85+
const type = s.Const('Hello');
86+
const type2: ConstSchema<'Hello'> = type;
87+
expect(type2).toEqual({
88+
kind: 'const',
89+
value: 'Hello',
90+
});
91+
});
92+
});

src/schema/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import type {TypeOf} from './schema';
12
import {SchemaBuilder} from './SchemaBuilder';
23

34
export * from './common';
45
export * from './schema';
56

67
/**
7-
* JSON Type AST builder.
8+
* JSON Type default AST builder.
89
*/
910
export const s = new SchemaBuilder();
11+
12+
export namespace s {
13+
export type infer<T> = TypeOf<T>;
14+
}

src/schema/schema.ts

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ export interface TType<Value = unknown> extends Display, Partial<Identifiable> {
1616
*/
1717
meta?: Record<string, unknown>;
1818

19+
/**
20+
* Default value for this type. This may be used when the value is not provided
21+
* during validation or serialization. The default value should match the
22+
* type of this schema node.
23+
*/
24+
default?: Value;
25+
1926
/**
2027
* List of example usages of this type.
2128
*/
@@ -52,6 +59,17 @@ export interface WithValidator {
5259

5360
/**
5461
* Represents something of which type is not known.
62+
*
63+
* Example:
64+
*
65+
* ```json
66+
* {
67+
* "kind": "any",
68+
* "metadata": {
69+
* "description": "Any type"
70+
* }
71+
* }
72+
* ```
5573
*/
5674
export interface AnySchema extends TType<unknown>, WithValidator {
5775
kind: 'any';
@@ -65,13 +83,35 @@ export interface AnySchema extends TType<unknown>, WithValidator {
6583

6684
/**
6785
* Represents a JSON boolean.
86+
*
87+
* Example:
88+
*
89+
* ```json
90+
* {
91+
* "kind": "bool",
92+
* "meta": {
93+
* "description": "A boolean value"
94+
* }
95+
* }
96+
* ```
6897
*/
6998
export interface BooleanSchema extends TType<boolean>, WithValidator {
7099
kind: 'bool';
71100
}
72101

73102
/**
74103
* Represents a JSON number.
104+
*
105+
* Example:
106+
*
107+
* ```json
108+
* {
109+
* "kind": "num",
110+
* "format": "i32",
111+
* "gte": 0,
112+
* "lte": 100
113+
* }
114+
* ```
75115
*/
76116
export interface NumberSchema extends TType<number>, WithValidator {
77117
kind: 'num';
@@ -112,6 +152,17 @@ export interface NumberSchema extends TType<number>, WithValidator {
112152

113153
/**
114154
* Represents a JSON string.
155+
*
156+
* Example:
157+
*
158+
* ```json
159+
* {
160+
* "kind": "str",
161+
* "format": "utf8",
162+
* "min": 1,
163+
* "max": 255
164+
* }
165+
* ```
115166
*/
116167
export interface StringSchema extends TType<string>, WithValidator {
117168
kind: 'str';
@@ -150,6 +201,20 @@ export interface StringSchema extends TType<string>, WithValidator {
150201

151202
/**
152203
* Represents a binary type.
204+
*
205+
* Example:
206+
*
207+
* ```json
208+
* {
209+
* "kind": "bin",
210+
* "type": {
211+
* "kind": "str"
212+
* },
213+
* "format": "json",
214+
* "min": 10,
215+
* "max": 1024
216+
* }
217+
* ```
153218
*/
154219
export interface BinarySchema<T extends TType = any> extends TType, WithValidator {
155220
kind: 'bin';
@@ -169,6 +234,19 @@ export interface BinarySchema<T extends TType = any> extends TType, WithValidato
169234

170235
/**
171236
* Represents a JSON array.
237+
*
238+
* Example:
239+
*
240+
* ```json
241+
* {
242+
* "kind": "arr",
243+
* "type": {
244+
* "kind": "num"
245+
* },
246+
* "min": 1,
247+
* "max": 10
248+
* }
249+
* ```
172250
*/
173251
export interface ArraySchema<T extends TType = any> extends TType<Array<unknown>>, WithValidator {
174252
kind: 'arr';
@@ -182,6 +260,13 @@ export interface ArraySchema<T extends TType = any> extends TType<Array<unknown>
182260

183261
/**
184262
* Represents a constant value.
263+
* Example:
264+
* ```json
265+
* {
266+
* "kind": "const",
267+
* "value": 42
268+
* }
269+
* ```
185270
*/
186271
export interface ConstSchema<V = any> extends TType, WithValidator {
187272
/** @todo Rename to "con". */
@@ -202,6 +287,32 @@ export interface TupleSchema<T extends TType[] = any> extends TType, WithValidat
202287
/**
203288
* Represents a JSON object type, the "object" type excluding "null" in JavaScript,
204289
* the "object" type in JSON Schema, and the "obj" type in MessagePack.
290+
* Example:
291+
* ```json
292+
* {
293+
* "kind": "obj",
294+
* "fields": [
295+
* {
296+
* "kind": "field",
297+
* "key": "name",
298+
* "type": {
299+
* "kind": "str"
300+
* },
301+
* "optional": false
302+
* },
303+
* {
304+
* "kind": "field",
305+
* "key": "age",
306+
* "type": {
307+
* "kind": "num",
308+
* "gte": 0
309+
* },
310+
* "optional": true
311+
* }
312+
* ],
313+
* "unknownFields": false
314+
* }
315+
* ```
205316
*/
206317
export interface ObjectSchema<
207318
Fields extends ObjectFieldSchema<string, TType>[] | readonly ObjectFieldSchema<string, TType>[] = any,
@@ -246,8 +357,14 @@ export interface ObjectFieldSchema<K extends string = string, V extends TType =
246357
kind: 'field';
247358
/** Key name of the field. */
248359
key: K;
249-
/** One or more "one-of" types of the field. */
360+
361+
/**
362+
* One or more "one-of" types of the field.
363+
*
364+
* @todo Rename to `val`.
365+
*/
250366
type: V;
367+
251368
optional?: boolean;
252369
}
253370

@@ -262,7 +379,11 @@ export interface ObjectOptionalFieldSchema<K extends string = string, V extends
262379
*/
263380
export interface MapSchema<T extends TType = any> extends TType<Record<string, unknown>>, WithValidator {
264381
kind: 'map';
265-
/** Type of all values in the map. */
382+
/**
383+
* Type of all values in the map.
384+
*
385+
* @todo Rename to `val`. And add `key` field for the key type. Make `key` default to `str`.
386+
*/
266387
type: T;
267388
}
268389

@@ -299,6 +420,7 @@ export interface FunctionSchema<Req extends TType = TType, Res extends TType = T
299420
export type FunctionStreamingValue<Req, Res, Ctx = unknown> = (req: Observable<Req>, ctx?: Ctx) => Observable<Res>;
300421

301422
export interface FunctionStreamingSchema<Req extends TType = TType, Res extends TType = TType> extends TType {
423+
/** @todo Rename to `fn`. Make it a property on the schema instead. */
302424
kind: 'fn$';
303425
req: Req;
304426
res: Res;
@@ -396,3 +518,8 @@ export type OptionalProps<T extends object> = Exclude<
396518

397519
export type Optional<T extends object> = Pick<T, OptionalProps<T>>;
398520
export type Required<T extends object> = Omit<T, OptionalProps<T>>;
521+
522+
export type Narrow<T> =
523+
| (T extends infer U ? U : never)
524+
| Extract<T, number | string | boolean | bigint | symbol | null | undefined | []>
525+
| ([T] extends [[]] ? [] : {[K in keyof T]: Narrow<T[K]>});

src/system/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ export type ResolveType<T> = T extends TypeAlias<any, infer T>
2323
: T extends Schema
2424
? TypeOf<T>
2525
: never;
26+
27+
export type infer<T> = ResolveType<T>;

0 commit comments

Comments
 (0)