@lucania/schema 3.0.4 → 3.1.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 +674 -674
- package/README.md +126 -126
- package/build/builder.d.ts +12 -14
- package/build/index.js +5 -43
- package/build/schema/EnumerationSchema.d.ts +8 -6
- package/build/schema/OrSetSchema.d.ts +8 -8
- package/build/schema/TupleSchema.d.ts +20 -0
- package/build/typing/extended.d.ts +1 -1
- package/package.json +40 -40
package/README.md
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
# Schema
|
|
2
|
-
|
|
3
|
-
| TECHNICAL | |
|
|
4
|
-
| :-------: | -------------------------------------------------------------------------- |
|
|
5
|
-
| _noun_ | _a representation of a plan or theory in the form of an outline or model._ |
|
|
6
|
-
|
|
7
|
-
This library allows you to specify the schema for your data, and get compile time typings _(help from your IDE)_ and runtime validation _(throw errors if your data isn't in the right format)_.
|
|
8
|
-
|
|
9
|
-
With this library, you create objects that serve as a blueprint for what your data should look like. These objects are called `Schema`s.
|
|
10
|
-
|
|
11
|
-
| _Schema Type_ | Description | Usage | Example Data |
|
|
12
|
-
| :-------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
|
|
13
|
-
| `StringSchema` | Used to represent a string. | `$.String(required?: boolean, default?: StringSource)` | `"Moaaz"`, `"The cow jumped over the moon."` |
|
|
14
|
-
| `NumberSchema` | Used to represent a number. | `$.Number(required?: boolean, default?: NumberSource)` | `-30`, `0`, `10` |
|
|
15
|
-
| `BooleanSchema` | Used to represent a boolean. | `$.Boolean(required?: boolean, default?: BooleanSource)` | `true`, `false` |
|
|
16
|
-
| `DateSchema` | Used to represent a Date. | `$.Date(required?: boolean, default?: DateSource)` | `new Date(2000, 9, 29)`, `new Date("1998-09-04")` |
|
|
17
|
-
| `ObjectSchema` | Used to represent an Object. | `$.Object(subschema: { <key>: Schema }, required?: boolean, default?: ObjectSource)` | `<depends on subschema>`, `{ name: "Jeremy", age: 23 }`, `{ make: "Toyota", model: "Sienna", year: 2011 }` |
|
|
18
|
-
| `ArraySchema` | Used to represent an array | `$.Array(subschema: Schema, required?: boolean, default?: ArraySource)` | `<depends on subschema>`, `[]`, `[1, 2, 3]`, `["Ben", "Amit", "Dean"]` |
|
|
19
|
-
| `EnumerationSchema` | Used to represent an enumeration value, otherwise known as a set of possible strings values. | `$.Enumeration(members: Members, required?: boolean, default?: EnumerationSource)` | `<depends on members>`, `"MAGENTA"`, `"CA"`, `"male"` |
|
|
20
|
-
| `OrSetSchema` | Used to represent a value that should be validated by one of many possible schemas. This is used to represent a value that is allowed to be multiple types. | `$.OrSet(members: Members, required?: boolean, default?: OrSetSource)` | `<depends on members>` |
|
|
21
|
-
| `DynamicObjectSchema` | Used to represent an object that could have many different keys. | `$.DynamicObject(subschema: Schema, required?: boolean, default?: DynamicObjectSource)` | `{ <any key>: <depends on subschema> }` |
|
|
22
|
-
| `AnySchema` | Used to represent a value that could be any type. | `$.Any(required?: boolean, default?: AnySource)` | `1`, `"Omar"`, `false`, `{}`, `[]`, `<any type>` |
|
|
23
|
-
|
|
24
|
-
## Validation
|
|
25
|
-
|
|
26
|
-
The simplest possible validation:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { $ } from "@lucania/schema";
|
|
30
|
-
|
|
31
|
-
// Create a Schema to represent a number.
|
|
32
|
-
const numberSchema = $.Number();
|
|
33
|
-
|
|
34
|
-
// Some data with an unknown type, likely coming from a file, network or untyped library.
|
|
35
|
-
const dataOfUnknownType: any = 123;
|
|
36
|
-
|
|
37
|
-
// Using our number Schema to validate that our untyped data is what we expect it to be, a number. "dataOfNumberType" now has the "number" type.
|
|
38
|
-
const dataOfNumberType = numberSchema.validate(dataOfUnknownType);
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
With this collection of Schemas, we can now start building more complex data structures. There are multiple way to represent different scenarios. This is done with the following constructs.
|
|
42
|
-
|
|
43
|
-
## Creating Hierarchical Schema
|
|
44
|
-
|
|
45
|
-
These schemas can come together to allow you to define a blueprint for more complex data structures.
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
import { $ } from "@lucania/schema";
|
|
49
|
-
|
|
50
|
-
const WeaponSchema = $.Object({
|
|
51
|
-
damage: $.Number(true).clamp(0, 100),
|
|
52
|
-
forged: $.Date(false),
|
|
53
|
-
affixtures: $.DynamicObject($.String())
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const PersonSchema = $.Object({
|
|
57
|
-
name: $.Object({
|
|
58
|
-
first: $.String(true),
|
|
59
|
-
middle: $.String(false),
|
|
60
|
-
last: $.String(true)
|
|
61
|
-
}),
|
|
62
|
-
favoriteNumber: $.Number(true).ensure((data, pass) => data % 2 === 0, "Your favorite number must be a multiple of 2!"),
|
|
63
|
-
age: $.Number(true).min(16, "You must be at least 16 years old!").max(100, "You must be at most 100 years old!"),
|
|
64
|
-
weapon: WeaponSchema
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Using Schema
|
|
69
|
-
|
|
70
|
-
With the schema definitions created, they can be used to validate data where the types are unknown. This data might come from fetch requests, information read from disk, or even JavaScript libraries that don't export their own type definitions, just to name a few examples.
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
import fs from "fs";
|
|
74
|
-
|
|
75
|
-
const personData = JSON.parse(fs.readFileSync("person.json", "utf8"));
|
|
76
|
-
const person = PersonSchema.validate(personData);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
`person` now has the following compile-time type annotation based on [`PersonSchema`](#creating-hierarchical-schema).
|
|
80
|
-
|
|
81
|
-
At runtime, the object parsed from the `person.json` file will be validated to match this generated typing. If it does not match, a `Schema.ValidationError` will be thrown.
|
|
82
|
-
|
|
83
|
-
## Additional Validation Passes
|
|
84
|
-
|
|
85
|
-
Sometimes it's necessary to validate not only a type, but also specifics about the value. I.E. a value is a `$.Number` _and_ is between 0 and 100. You can add additional type-specific validation passes (I.E. `.clamp(...)`) or custom ones (`.custom(...)`):
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
const numberData: any = ...;
|
|
89
|
-
|
|
90
|
-
const ScoreSchema = $.Number().clamp(0, 100).custom((data, pass) => {
|
|
91
|
-
pass.assert(data % 2 === 0, "Your score must be even!");
|
|
92
|
-
return data;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// The above custom() validation pass can alternately be defined using the .ensure() shorthand.
|
|
96
|
-
|
|
97
|
-
const ScoreSchema = $.Number().clamp(0, 100).ensure((data, pass) => data % 2 === 0, "Your score must be even!");
|
|
98
|
-
|
|
99
|
-
const number: number = ScoreSchema.validate(numberData);
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Custom Schema Types
|
|
103
|
-
|
|
104
|
-
You can define your own Schema types by creating a subclass of `BaseSchema`. But first, `BaseSchema` relies on 4 generic parameters for TypeScript's type checker to understand your Schema at compile time. These parameters are as follows:
|
|
105
|
-
|
|
106
|
-
- Source - Represents the typing for a source input to your schema.
|
|
107
|
-
- Model - Represents the typing for an output value from your schema.
|
|
108
|
-
- Required - Represents the presence optionality of your schema's Source/Model. (Is `undefined` a valid Source and Model)
|
|
109
|
-
- Default - Represents the typing for default values.
|
|
110
|
-
|
|
111
|
-
Typically, when developing your own Schema types, you'll hardcode Source and Model for your specific Schema's requirements, but pass over `Required` and `Default` generics to `BaseSchema` to allow them to be inferred from your Schema definitions.
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
export type CowModel = { name: string, numberOfSpots: number };
|
|
115
|
-
|
|
116
|
-
export type CowSource = string | CowModel;
|
|
117
|
-
|
|
118
|
-
export class CowSchema<
|
|
119
|
-
Required extends boolean, // Taking in "Required" generic.
|
|
120
|
-
Default extends DefaultValue<CowSource> // Taking in "Default" generic.
|
|
121
|
-
|
|
122
|
-
// Handing over hardcoded Source, Model and CowSchema generics to BaseSchema.
|
|
123
|
-
> extends BaseSchema<CowSource, CowModel, Required, Default> { ... }
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
These declarations are enough to have the TypeScript type checker understand the compile-time typing for `CowSchema`. Next, lets implement our runtime checks.
|
|
1
|
+
# Schema
|
|
2
|
+
|
|
3
|
+
| TECHNICAL | |
|
|
4
|
+
| :-------: | -------------------------------------------------------------------------- |
|
|
5
|
+
| _noun_ | _a representation of a plan or theory in the form of an outline or model._ |
|
|
6
|
+
|
|
7
|
+
This library allows you to specify the schema for your data, and get compile time typings _(help from your IDE)_ and runtime validation _(throw errors if your data isn't in the right format)_.
|
|
8
|
+
|
|
9
|
+
With this library, you create objects that serve as a blueprint for what your data should look like. These objects are called `Schema`s.
|
|
10
|
+
|
|
11
|
+
| _Schema Type_ | Description | Usage | Example Data |
|
|
12
|
+
| :-------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
|
|
13
|
+
| `StringSchema` | Used to represent a string. | `$.String(required?: boolean, default?: StringSource)` | `"Moaaz"`, `"The cow jumped over the moon."` |
|
|
14
|
+
| `NumberSchema` | Used to represent a number. | `$.Number(required?: boolean, default?: NumberSource)` | `-30`, `0`, `10` |
|
|
15
|
+
| `BooleanSchema` | Used to represent a boolean. | `$.Boolean(required?: boolean, default?: BooleanSource)` | `true`, `false` |
|
|
16
|
+
| `DateSchema` | Used to represent a Date. | `$.Date(required?: boolean, default?: DateSource)` | `new Date(2000, 9, 29)`, `new Date("1998-09-04")` |
|
|
17
|
+
| `ObjectSchema` | Used to represent an Object. | `$.Object(subschema: { <key>: Schema }, required?: boolean, default?: ObjectSource)` | `<depends on subschema>`, `{ name: "Jeremy", age: 23 }`, `{ make: "Toyota", model: "Sienna", year: 2011 }` |
|
|
18
|
+
| `ArraySchema` | Used to represent an array | `$.Array(subschema: Schema, required?: boolean, default?: ArraySource)` | `<depends on subschema>`, `[]`, `[1, 2, 3]`, `["Ben", "Amit", "Dean"]` |
|
|
19
|
+
| `EnumerationSchema` | Used to represent an enumeration value, otherwise known as a set of possible strings values. | `$.Enumeration(members: Members, required?: boolean, default?: EnumerationSource)` | `<depends on members>`, `"MAGENTA"`, `"CA"`, `"male"` |
|
|
20
|
+
| `OrSetSchema` | Used to represent a value that should be validated by one of many possible schemas. This is used to represent a value that is allowed to be multiple types. | `$.OrSet(members: Members, required?: boolean, default?: OrSetSource)` | `<depends on members>` |
|
|
21
|
+
| `DynamicObjectSchema` | Used to represent an object that could have many different keys. | `$.DynamicObject(subschema: Schema, required?: boolean, default?: DynamicObjectSource)` | `{ <any key>: <depends on subschema> }` |
|
|
22
|
+
| `AnySchema` | Used to represent a value that could be any type. | `$.Any(required?: boolean, default?: AnySource)` | `1`, `"Omar"`, `false`, `{}`, `[]`, `<any type>` |
|
|
23
|
+
|
|
24
|
+
## Validation
|
|
25
|
+
|
|
26
|
+
The simplest possible validation:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { $ } from "@lucania/schema";
|
|
30
|
+
|
|
31
|
+
// Create a Schema to represent a number.
|
|
32
|
+
const numberSchema = $.Number();
|
|
33
|
+
|
|
34
|
+
// Some data with an unknown type, likely coming from a file, network or untyped library.
|
|
35
|
+
const dataOfUnknownType: any = 123;
|
|
36
|
+
|
|
37
|
+
// Using our number Schema to validate that our untyped data is what we expect it to be, a number. "dataOfNumberType" now has the "number" type.
|
|
38
|
+
const dataOfNumberType = numberSchema.validate(dataOfUnknownType);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
With this collection of Schemas, we can now start building more complex data structures. There are multiple way to represent different scenarios. This is done with the following constructs.
|
|
42
|
+
|
|
43
|
+
## Creating Hierarchical Schema
|
|
44
|
+
|
|
45
|
+
These schemas can come together to allow you to define a blueprint for more complex data structures.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { $ } from "@lucania/schema";
|
|
49
|
+
|
|
50
|
+
const WeaponSchema = $.Object({
|
|
51
|
+
damage: $.Number(true).clamp(0, 100),
|
|
52
|
+
forged: $.Date(false),
|
|
53
|
+
affixtures: $.DynamicObject($.String())
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const PersonSchema = $.Object({
|
|
57
|
+
name: $.Object({
|
|
58
|
+
first: $.String(true),
|
|
59
|
+
middle: $.String(false),
|
|
60
|
+
last: $.String(true)
|
|
61
|
+
}),
|
|
62
|
+
favoriteNumber: $.Number(true).ensure((data, pass) => data % 2 === 0, "Your favorite number must be a multiple of 2!"),
|
|
63
|
+
age: $.Number(true).min(16, "You must be at least 16 years old!").max(100, "You must be at most 100 years old!"),
|
|
64
|
+
weapon: WeaponSchema
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Using Schema
|
|
69
|
+
|
|
70
|
+
With the schema definitions created, they can be used to validate data where the types are unknown. This data might come from fetch requests, information read from disk, or even JavaScript libraries that don't export their own type definitions, just to name a few examples.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import fs from "fs";
|
|
74
|
+
|
|
75
|
+
const personData = JSON.parse(fs.readFileSync("person.json", "utf8"));
|
|
76
|
+
const person = PersonSchema.validate(personData);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`person` now has the following compile-time type annotation based on [`PersonSchema`](#creating-hierarchical-schema).
|
|
80
|
+
|
|
81
|
+
At runtime, the object parsed from the `person.json` file will be validated to match this generated typing. If it does not match, a `Schema.ValidationError` will be thrown.
|
|
82
|
+
|
|
83
|
+
## Additional Validation Passes
|
|
84
|
+
|
|
85
|
+
Sometimes it's necessary to validate not only a type, but also specifics about the value. I.E. a value is a `$.Number` _and_ is between 0 and 100. You can add additional type-specific validation passes (I.E. `.clamp(...)`) or custom ones (`.custom(...)`):
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const numberData: any = ...;
|
|
89
|
+
|
|
90
|
+
const ScoreSchema = $.Number().clamp(0, 100).custom((data, pass) => {
|
|
91
|
+
pass.assert(data % 2 === 0, "Your score must be even!");
|
|
92
|
+
return data;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// The above custom() validation pass can alternately be defined using the .ensure() shorthand.
|
|
96
|
+
|
|
97
|
+
const ScoreSchema = $.Number().clamp(0, 100).ensure((data, pass) => data % 2 === 0, "Your score must be even!");
|
|
98
|
+
|
|
99
|
+
const number: number = ScoreSchema.validate(numberData);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Custom Schema Types
|
|
103
|
+
|
|
104
|
+
You can define your own Schema types by creating a subclass of `BaseSchema`. But first, `BaseSchema` relies on 4 generic parameters for TypeScript's type checker to understand your Schema at compile time. These parameters are as follows:
|
|
105
|
+
|
|
106
|
+
- Source - Represents the typing for a source input to your schema.
|
|
107
|
+
- Model - Represents the typing for an output value from your schema.
|
|
108
|
+
- Required - Represents the presence optionality of your schema's Source/Model. (Is `undefined` a valid Source and Model)
|
|
109
|
+
- Default - Represents the typing for default values.
|
|
110
|
+
|
|
111
|
+
Typically, when developing your own Schema types, you'll hardcode Source and Model for your specific Schema's requirements, but pass over `Required` and `Default` generics to `BaseSchema` to allow them to be inferred from your Schema definitions.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
export type CowModel = { name: string, numberOfSpots: number };
|
|
115
|
+
|
|
116
|
+
export type CowSource = string | CowModel;
|
|
117
|
+
|
|
118
|
+
export class CowSchema<
|
|
119
|
+
Required extends boolean, // Taking in "Required" generic.
|
|
120
|
+
Default extends DefaultValue<CowSource> // Taking in "Default" generic.
|
|
121
|
+
|
|
122
|
+
// Handing over hardcoded Source, Model and CowSchema generics to BaseSchema.
|
|
123
|
+
> extends BaseSchema<CowSource, CowModel, Required, Default> { ... }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
These declarations are enough to have the TypeScript type checker understand the compile-time typing for `CowSchema`. Next, lets implement our runtime checks.
|
package/build/builder.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { BaseSchema, SourceValue } from ".";
|
|
2
1
|
import { AnySchema } from "./schema/AnySchema";
|
|
3
2
|
import { ArraySchema, ArraySource } from "./schema/ArraySchema";
|
|
3
|
+
import { BaseSchema } from "./schema/BaseSchema";
|
|
4
4
|
import { BooleanSchema, BooleanSource } from "./schema/BooleanSchema";
|
|
5
5
|
import { ConstantSchema, ConstantSource } from "./schema/ConstantSchema";
|
|
6
6
|
import { DateSchema, DateSource } from "./schema/DateSchema";
|
|
7
7
|
import { DynamicObjectSchema, DynamicObjectSource } from "./schema/DynamicObjectSchema";
|
|
8
|
-
import { EnumerationSchema } from "./schema/EnumerationSchema";
|
|
8
|
+
import { EnumerationSchema, EnumerationSource } from "./schema/EnumerationSchema";
|
|
9
9
|
import { LenientObjectModel, LenientObjectSchema, LenientObjectSource, LenientObjectSubschema } from "./schema/LenientObject";
|
|
10
10
|
import { NumberSchema, NumberSource } from "./schema/NumberSchema";
|
|
11
11
|
import { ObjectSchema, ObjectSource, ObjectSubschema } from "./schema/ObjectSchema";
|
|
12
12
|
import { OrSetSchema, OrSetSchemaSource } from "./schema/OrSetSchema";
|
|
13
13
|
import { StringSchema, StringSource } from "./schema/StringSchema";
|
|
14
14
|
import { BaseSchemaAny } from "./typing/extended";
|
|
15
|
-
import { DefaultValue, ModelValue } from "./typing/toolbox";
|
|
15
|
+
import { DefaultValue, ModelValue, SourceValue } from "./typing/toolbox";
|
|
16
16
|
/**
|
|
17
17
|
* A collection of helper functions used to create the standard set of schemas.
|
|
18
18
|
*/
|
|
@@ -144,21 +144,19 @@ export declare namespace Schema {
|
|
|
144
144
|
function Array<Subschema extends BaseSchemaAny>(subschema: Subschema): ArraySchema<Subschema, true, undefined>;
|
|
145
145
|
function Array<Subschema extends BaseSchemaAny, Required extends boolean>(subschema: Subschema, required: Required): ArraySchema<Subschema, Required, undefined>;
|
|
146
146
|
function Array<Subschema extends BaseSchemaAny, Required extends boolean, Default extends DefaultValue<ArraySource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): ArraySchema<Subschema, Required, Default>;
|
|
147
|
-
function Enumeration<
|
|
148
|
-
function Enumeration<
|
|
149
|
-
function Enumeration<
|
|
150
|
-
function OrSet<
|
|
151
|
-
function OrSet<
|
|
152
|
-
function OrSet<
|
|
147
|
+
function Enumeration<Members extends string[]>(subschema: TypedMembers<Members>): EnumerationSchema<Members, true, undefined>;
|
|
148
|
+
function Enumeration<Members extends string[], Required extends boolean>(subschema: TypedMembers<Members>, required: Required): EnumerationSchema<Members, Required, undefined>;
|
|
149
|
+
function Enumeration<Members extends string[], Required extends boolean, Default extends DefaultValue<EnumerationSource<Members>>>(subschema: TypedMembers<Members>, required: Required, defaultValue: Default): EnumerationSchema<Members, Required, Default>;
|
|
150
|
+
function OrSet<MemberSchemas extends BaseSchemaAny[]>(subschema: TypedMembers<MemberSchemas>): OrSetSchema<MemberSchemas, true, undefined>;
|
|
151
|
+
function OrSet<MemberSchemas extends BaseSchemaAny[], Required extends boolean>(subschema: TypedMembers<MemberSchemas>, required: Required): OrSetSchema<MemberSchemas, Required, undefined>;
|
|
152
|
+
function OrSet<MemberSchemas extends BaseSchemaAny[], Required extends boolean, Default extends DefaultValue<OrSetSchemaSource<MemberSchemas>>>(subschema: TypedMembers<MemberSchemas>, required: Required, defaultValue: Default): OrSetSchema<MemberSchemas, Required, Default>;
|
|
153
153
|
function Constant<Constant extends ConstantSource>(constant: Constant): ConstantSchema<Constant, true, undefined>;
|
|
154
154
|
function Constant<Constant extends ConstantSource, Required extends boolean>(constant: Constant, required: Required): ConstantSchema<Constant, Required, undefined>;
|
|
155
155
|
function Constant<Constant extends ConstantSource, Required extends boolean, Default extends DefaultValue<Constant>>(constant: Constant, required: Required, defaultValue: Default): ConstantSchema<Constant, Required, Default>;
|
|
156
|
-
type TypedMembers<
|
|
157
|
-
$members:
|
|
156
|
+
type TypedMembers<Members extends readonly any[]> = {
|
|
157
|
+
$members: Members;
|
|
158
158
|
};
|
|
159
|
-
function Members<
|
|
160
|
-
function Members<Member extends number[]>(...members: Member): TypedMembers<Member[number]>;
|
|
161
|
-
function Members<Member extends any[]>(...members: Member): TypedMembers<Member[number]>;
|
|
159
|
+
function Members<const Members extends any[]>(...members: Members): TypedMembers<Members>;
|
|
162
160
|
function Keys<Object extends object>(object: Object): (keyof Object)[];
|
|
163
161
|
function Values<Object extends object>(object: Object): (Object[keyof Object])[];
|
|
164
162
|
type Model<Schema extends BaseSchemaAny> = Schema extends BaseSchema<infer Source, infer Model, infer Require, infer Default> ? (ModelValue<Source, Model, Require, Default>) : never;
|
package/build/index.js
CHANGED
|
@@ -755,7 +755,7 @@
|
|
|
755
755
|
this.schemas = schemas;
|
|
756
756
|
}
|
|
757
757
|
get type() {
|
|
758
|
-
return "
|
|
758
|
+
return "OrSet";
|
|
759
759
|
}
|
|
760
760
|
_validate(source, options, pass) {
|
|
761
761
|
const errors = {};
|
|
@@ -775,35 +775,6 @@
|
|
|
775
775
|
throw pass.causeError(`Provided value (${BaseSchema.getType(source)}) matched no schemas ` +
|
|
776
776
|
`(${this.schemas.map((schema) => schema.type).join(", ")}).\n` +
|
|
777
777
|
`${errorMessages.join("\n")}`);
|
|
778
|
-
// let result = source;
|
|
779
|
-
// if (result !== undefined) {
|
|
780
|
-
// let done = false;
|
|
781
|
-
// const failureMessages: string[] = [];
|
|
782
|
-
// for (let i = 0; i < this.schemas.length && !done; i++) {
|
|
783
|
-
// const schema = this.schemas[i];
|
|
784
|
-
// try {
|
|
785
|
-
// if (BaseSchema.getType(result) === schema.type) {
|
|
786
|
-
// result = schema.validate(result, options, pass);
|
|
787
|
-
// done = true;
|
|
788
|
-
// }
|
|
789
|
-
// } catch (error) {
|
|
790
|
-
// if (error instanceof Error) {
|
|
791
|
-
// failureMessages.push(`Schema #${i + 1}: ${error.message}`);
|
|
792
|
-
// } else {
|
|
793
|
-
// failureMessages.push(`Schema #${i + 1}: ${String(error)}`);
|
|
794
|
-
// }
|
|
795
|
-
// }
|
|
796
|
-
// }
|
|
797
|
-
// if (!done) {
|
|
798
|
-
// failureMessages.push(`Conversions for schemas in an OrSet are disabled.`);
|
|
799
|
-
// }
|
|
800
|
-
// pass.assert(
|
|
801
|
-
// failureMessages.length === 0,
|
|
802
|
-
// `Provided value (${BaseSchema.getType(result)}) matched no schemas ` +
|
|
803
|
-
// `(${this.schemas.map((schema) => schema.type).join(", ")}).\n${failureMessages.join("\n")}`
|
|
804
|
-
// );
|
|
805
|
-
// }
|
|
806
|
-
// return result;
|
|
807
778
|
}
|
|
808
779
|
convert(value, pass) {
|
|
809
780
|
return value;
|
|
@@ -926,12 +897,12 @@
|
|
|
926
897
|
return new ArraySchema(subschema, required, defaultValue);
|
|
927
898
|
}
|
|
928
899
|
Schema.Array = Array;
|
|
929
|
-
function Enumeration(members, required = true, defaultValue = undefined) {
|
|
930
|
-
return new EnumerationSchema(members
|
|
900
|
+
function Enumeration({ $members }, required = true, defaultValue = undefined) {
|
|
901
|
+
return new EnumerationSchema($members, required, defaultValue);
|
|
931
902
|
}
|
|
932
903
|
Schema.Enumeration = Enumeration;
|
|
933
|
-
function OrSet(members, required = true, defaultValue = undefined) {
|
|
934
|
-
return new OrSetSchema(members
|
|
904
|
+
function OrSet({ $members }, required = true, defaultValue = undefined) {
|
|
905
|
+
return new OrSetSchema($members, required, defaultValue);
|
|
935
906
|
}
|
|
936
907
|
Schema.OrSet = OrSet;
|
|
937
908
|
function Constant(value, required = true, defaultValue = undefined) {
|
|
@@ -939,15 +910,6 @@
|
|
|
939
910
|
}
|
|
940
911
|
Schema.Constant = Constant;
|
|
941
912
|
function Members(...members) {
|
|
942
|
-
/*
|
|
943
|
-
* HACK START: The hermes JS engine doesn't use globalThis.Array when interpreting `...members`
|
|
944
|
-
* It uses `Array`, which is already defined in this namespace.
|
|
945
|
-
*/
|
|
946
|
-
if (!globalThis.Array.isArray(members)) {
|
|
947
|
-
const validArrayEntries = globalThis.Object.entries(members).filter(([key]) => !isNaN(key));
|
|
948
|
-
members = validArrayEntries.map(([_, value]) => value);
|
|
949
|
-
}
|
|
950
|
-
/* HACK END */
|
|
951
913
|
return { $members: members };
|
|
952
914
|
}
|
|
953
915
|
Schema.Members = Members;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { ValidationPass } from "../error/ValidationPass";
|
|
2
|
-
import { AdditionalValidationPasses, DefaultValue, ModelValue, ValidationOptions } from "../typing/toolbox";
|
|
2
|
+
import { AdditionalValidationPasses, DefaultValue, ModelValue, SourceValue, ValidationOptions } from "../typing/toolbox";
|
|
3
3
|
import { BaseSchema } from "./BaseSchema";
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export type EnumerationSource<Members extends string[]> = Members[number];
|
|
5
|
+
export type EnumerationModel<Members extends string[]> = Members[number];
|
|
6
|
+
export declare class EnumerationSchema<Members extends string[], Required extends boolean, Default extends DefaultValue<EnumerationSource<Members>>> extends BaseSchema<EnumerationSource<Members>, EnumerationModel<Members>, Required, Default> {
|
|
7
|
+
readonly members: Members;
|
|
8
|
+
constructor(members: Members, required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<Members[number], Members[number]>);
|
|
7
9
|
get type(): string;
|
|
8
|
-
protected _validate(source:
|
|
9
|
-
convert(value: Members
|
|
10
|
+
protected _validate(source: SourceValue<EnumerationSource<Members>, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<EnumerationSource<Members>, EnumerationModel<Members>, Required, Default>;
|
|
11
|
+
convert(value: EnumerationSource<Members>, pass: ValidationPass): EnumerationModel<Members>;
|
|
10
12
|
clone(): EnumerationSchema<Members, Required, Default>;
|
|
11
13
|
getJsonSchema(): object;
|
|
12
14
|
}
|
|
@@ -2,14 +2,14 @@ import { ValidationPass } from "../error/ValidationPass";
|
|
|
2
2
|
import { BaseSchemaAny } from "../typing/extended";
|
|
3
3
|
import { AdditionalValidationPasses, DefaultValue, ModelValue, SourceValue, ValidationOptions } from "../typing/toolbox";
|
|
4
4
|
import { BaseSchema } from "./BaseSchema";
|
|
5
|
-
export type OrSetSchemaSource<
|
|
6
|
-
export type OrSetSchemaModel<
|
|
7
|
-
export declare class OrSetSchema<
|
|
8
|
-
readonly schemas:
|
|
9
|
-
constructor(schemas:
|
|
5
|
+
export type OrSetSchemaSource<MemberSchemas extends BaseSchemaAny[]> = (MemberSchemas[number] extends infer MemberSchema ? (MemberSchema extends BaseSchema<infer Source, any, infer Required, infer Default> ? (SourceValue<Source, Required, Default>) : never) : never);
|
|
6
|
+
export type OrSetSchemaModel<MemberSchemas extends BaseSchemaAny[]> = (MemberSchemas[number] extends infer MemberSchema ? (MemberSchema extends BaseSchema<infer Source, infer Model, infer Required, infer Default> ? (ModelValue<Source, Model, Required, Default>) : never) : never);
|
|
7
|
+
export declare class OrSetSchema<MemberSchemas extends BaseSchemaAny[], Required extends boolean, Default extends DefaultValue<OrSetSchemaSource<MemberSchemas>>> extends BaseSchema<OrSetSchemaSource<MemberSchemas>, OrSetSchemaModel<MemberSchemas>, Required, Default> {
|
|
8
|
+
readonly schemas: MemberSchemas;
|
|
9
|
+
constructor(schemas: MemberSchemas, required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<OrSetSchemaSource<MemberSchemas>, OrSetSchemaModel<MemberSchemas>>);
|
|
10
10
|
get type(): string;
|
|
11
|
-
protected _validate(source: ModelValue<OrSetSchemaSource<
|
|
12
|
-
convert(value: OrSetSchemaSource<
|
|
13
|
-
clone(): OrSetSchema<
|
|
11
|
+
protected _validate(source: ModelValue<OrSetSchemaSource<MemberSchemas>, OrSetSchemaModel<MemberSchemas>, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<OrSetSchemaSource<MemberSchemas>, OrSetSchemaModel<MemberSchemas>, Required, Default>;
|
|
12
|
+
convert(value: OrSetSchemaSource<MemberSchemas>, pass: ValidationPass): OrSetSchemaModel<MemberSchemas>;
|
|
13
|
+
clone(): OrSetSchema<MemberSchemas, Required, Default>;
|
|
14
14
|
getJsonSchema(): object;
|
|
15
15
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ValidationPass } from "../error/ValidationPass";
|
|
2
|
+
import { BaseSchemaAny } from "../typing/extended";
|
|
3
|
+
import { AdditionalValidationPasses, DefaultValue, ModelValue, SourceValue, ValidationOptions } from "../typing/toolbox";
|
|
4
|
+
import { BaseSchema } from "./BaseSchema";
|
|
5
|
+
export type TupleSubschema = BaseSchemaAny[];
|
|
6
|
+
export type TupleSource<Subschema extends TupleSubschema> = ({
|
|
7
|
+
[Key in keyof Subschema]: (Subschema[Key] extends BaseSchema<infer Source, any, infer Required, infer Default> ? (SourceValue<Source, Required, Default>) : never);
|
|
8
|
+
});
|
|
9
|
+
export type TupleModel<Subschema extends TupleSubschema> = ({
|
|
10
|
+
[Key in keyof Subschema]: (Subschema[Key] extends BaseSchema<infer Source, infer Model, infer Required, infer Default> ? (ModelValue<Source, Model, Required, Default>) : never);
|
|
11
|
+
});
|
|
12
|
+
export declare class TupleSchema<Subschema extends BaseSchemaAny[], Required extends boolean, Default extends DefaultValue<TupleSource<Subschema>>> extends BaseSchema<TupleSource<Subschema>, TupleModel<Subschema>, Required, Default> {
|
|
13
|
+
readonly subschema: Subschema;
|
|
14
|
+
constructor(subschema: Subschema, required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<TupleSource<Subschema>, TupleModel<Subschema>>);
|
|
15
|
+
get type(): string;
|
|
16
|
+
protected _validate(source: ModelValue<TupleSource<Subschema>, TupleModel<Subschema>, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<TupleSource<Subschema>, TupleModel<Subschema>, Required, Default>;
|
|
17
|
+
convert(value: TupleSource<Subschema>, pass: ValidationPass): TupleModel<Subschema>;
|
|
18
|
+
clone(): TupleSchema<Subschema, Required, Default>;
|
|
19
|
+
getJsonSchema(): object;
|
|
20
|
+
}
|
|
@@ -4,4 +4,4 @@ import { ObjectSchema } from "../schema/ObjectSchema";
|
|
|
4
4
|
import { DefaultValue } from "./toolbox";
|
|
5
5
|
export type BaseSchemaAny = BaseSchema<any, any, boolean, DefaultValue<any>>;
|
|
6
6
|
export type ObjectSchemaAny = ObjectSchema<any, boolean, DefaultValue<any>>;
|
|
7
|
-
export type EnumerationSchemaAny = EnumerationSchema<string, boolean, DefaultValue<any>>;
|
|
7
|
+
export type EnumerationSchemaAny = EnumerationSchema<string[], boolean, DefaultValue<any>>;
|
package/package.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@lucania/schema",
|
|
3
|
-
"version": "3.0
|
|
4
|
-
"description": "A schema module for compile-time and runtime type checking.",
|
|
5
|
-
"main": "./build/index.js",
|
|
6
|
-
"types": "./build/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"/build"
|
|
9
|
-
],
|
|
10
|
-
"scripts": {
|
|
11
|
-
"setup": "npm install",
|
|
12
|
-
"clean": "
|
|
13
|
-
"build": "npx rollup --bundleConfigAsCjs --config rollup.config.js",
|
|
14
|
-
"build:clean": "npm run clean && npm run build",
|
|
15
|
-
"build:watch": "npx rollup --watch --bundleConfigAsCjs --config rollup.config.js",
|
|
16
|
-
"push": "npm run build:clean && npm publish --access public"
|
|
17
|
-
},
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/lucania-software/schema.git"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"Schema"
|
|
24
|
-
],
|
|
25
|
-
"author": "Jeremy Bankes",
|
|
26
|
-
"license": "GPL-3.0-or-later",
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/lucania-software/schema/issues"
|
|
29
|
-
},
|
|
30
|
-
"homepage": "https://github.com/lucania-software/schema#readme",
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@babel/preset-env": "^7.24.7",
|
|
33
|
-
"@rollup/plugin-typescript": "^11.1.6",
|
|
34
|
-
"@types/node": "^20.14.2",
|
|
35
|
-
"nodemon": "^3.1.3",
|
|
36
|
-
"rollup": "^4.18.0",
|
|
37
|
-
"tslib": "^2.6.3",
|
|
38
|
-
"typescript": "^5.4.5"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@lucania/schema",
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "A schema module for compile-time and runtime type checking.",
|
|
5
|
+
"main": "./build/index.js",
|
|
6
|
+
"types": "./build/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/build"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"setup": "npm install",
|
|
12
|
+
"clean": "rm -rf build",
|
|
13
|
+
"build": "npx rollup --bundleConfigAsCjs --config rollup.config.js",
|
|
14
|
+
"build:clean": "npm run clean && npm run build",
|
|
15
|
+
"build:watch": "npx rollup --watch --bundleConfigAsCjs --config rollup.config.js",
|
|
16
|
+
"push": "npm run build:clean && npm publish --access public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/lucania-software/schema.git"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"Schema"
|
|
24
|
+
],
|
|
25
|
+
"author": "Jeremy Bankes",
|
|
26
|
+
"license": "GPL-3.0-or-later",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/lucania-software/schema/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/lucania-software/schema#readme",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@babel/preset-env": "^7.24.7",
|
|
33
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
34
|
+
"@types/node": "^20.14.2",
|
|
35
|
+
"nodemon": "^3.1.3",
|
|
36
|
+
"rollup": "^4.18.0",
|
|
37
|
+
"tslib": "^2.6.3",
|
|
38
|
+
"typescript": "^5.4.5"
|
|
39
|
+
}
|
|
40
|
+
}
|