@travetto/schema 3.0.2 → 3.1.0-rc.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 +15 -24
- package/package.json +3 -3
- package/src/service/registry.ts +2 -1
- package/src/service/types.ts +4 -0
- package/src/validate/types.ts +8 -0
- package/src/validate/validator.ts +3 -2
- package/support/transform-util.ts +6 -0
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/schema/DOC.
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/schema/DOC.tsx and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# Schema
|
|
4
|
+
|
|
4
5
|
## Data type registry for runtime validation, reflection and binding.
|
|
5
6
|
|
|
6
7
|
**Install: @travetto/schema**
|
|
@@ -12,23 +13,18 @@ npm install @travetto/schema
|
|
|
12
13
|
yarn add @travetto/schema
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
This module's purpose is to allow for proper declaration and validation of data types, in the course of running a program. The framework defined here, is
|
|
16
|
-
leveraged in the [Configuration](https://github.com/travetto/travetto/tree/main/module/config#readme "Configuration support"), [Application](https://github.com/travetto/travetto/tree/main/module/app#readme "Application registration/management and run support."), [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module."), [OpenAPI Specification](https://github.com/travetto/travetto/tree/main/module/openapi#readme "OpenAPI integration support for the Travetto framework") and [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") modules. The schema is the backbone of all data transfer, as it helps to
|
|
17
|
-
provide validation on correctness of input, whether it is a rest request, command line inputs, or a configuration file.
|
|
16
|
+
This module's purpose is to allow for proper declaration and validation of data types, in the course of running a program. The framework defined here, is leveraged in the [Configuration](https://github.com/travetto/travetto/tree/main/module/config#readme "Configuration support"), [Command Line Interface](https://github.com/travetto/travetto/tree/main/module/cli#readme "CLI infrastructure for Travetto framework"), [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module."), [OpenAPI Specification](https://github.com/travetto/travetto/tree/main/module/openapi#readme "OpenAPI integration support for the Travetto framework") and [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") modules. The schema is the backbone of all data transfer, as it helps to provide validation on correctness of input, whether it is a rest request, command line inputs, or a configuration file.
|
|
18
17
|
|
|
19
18
|
This module provides a mechanism for registering classes and field level information as well the ability to apply that information at runtime.
|
|
20
19
|
|
|
21
20
|
## Registration
|
|
22
|
-
The registry's schema information is defined by [Typescript](https://typescriptlang.org) AST and only applies to classes registered with the [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) decoration.
|
|
21
|
+
The registry's schema information is defined by [Typescript](https://typescriptlang.org) AST and only applies to classes registered with the [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) decoration.
|
|
23
22
|
|
|
24
23
|
### Classes
|
|
25
24
|
The module utilizes AST transformations to collect schema information, and facilitate the registration process without user intervention. The class can also be described using providing a:
|
|
26
|
-
|
|
27
|
-
|
|
28
25
|
* `title` - definition of the schema
|
|
29
26
|
* `description` - detailed description of the schema
|
|
30
27
|
* `examples` - A set of examples as [JSON](https://www.json.org) or [YAML](https://en.wikipedia.org/wiki/YAML)
|
|
31
|
-
|
|
32
28
|
The `title` will be picked up from the [JSDoc](http://usejsdoc.org/about-getting-started.html) comments, and additionally all fields can be set using the [@Describe](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/common.ts#L15) decorator.
|
|
33
29
|
|
|
34
30
|
**Code: Sample User Schema**
|
|
@@ -66,8 +62,6 @@ User:
|
|
|
66
62
|
|
|
67
63
|
### Fields
|
|
68
64
|
This schema provides a powerful base for data binding and validation at runtime. Additionally there may be types that cannot be detected, or some information that the programmer would like to override. Below are the supported field decorators:
|
|
69
|
-
|
|
70
|
-
|
|
71
65
|
* [@Field](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L38) defines a field that will be serialized.
|
|
72
66
|
* [@Required](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L78) defines a that field should be required
|
|
73
67
|
* [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L85) defines the allowable values that a field can have
|
|
@@ -87,15 +81,11 @@ This schema provides a powerful base for data binding and validation at runtime.
|
|
|
87
81
|
* [@LongText](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L98) same as text, but expects longer form content
|
|
88
82
|
* [@Readonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L65) defines a that field should not be bindable external to the class
|
|
89
83
|
* [@Writeonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L59) defines a that field should not be exported in serialization, but that it can be bound to
|
|
90
|
-
|
|
91
|
-
Additionally, schemas can be nested to form more complex data structures that are able to bound and validated.
|
|
84
|
+
Additionally, schemas can be nested to form more complex data structures that are able to bound and validated.
|
|
92
85
|
|
|
93
86
|
Just like the class, all fields can be defined with
|
|
94
|
-
|
|
95
|
-
|
|
96
87
|
* `description` - detailed description of the schema
|
|
97
88
|
* `examples` - A set of examples as [JSON](https://www.json.org) or [YAML](https://en.wikipedia.org/wiki/YAML)
|
|
98
|
-
|
|
99
89
|
And similarly, the `description` will be picked up from the [JSDoc](http://usejsdoc.org/about-getting-started.html) comments, and additionally all fields can be set using the [@Describe](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/common.ts#L15) decorator.
|
|
100
90
|
|
|
101
91
|
## Binding/Validation
|
|
@@ -156,7 +146,6 @@ Person {
|
|
|
156
146
|
**Note**: Binding will attempt to convert/coerce types as much as possible to honor the pattern of Javascript and it's dynamic nature.
|
|
157
147
|
|
|
158
148
|
### Validation
|
|
159
|
-
|
|
160
149
|
Validation is very similar to binding, but instead of attempting to assign values, any mismatch or violation of the schema will result in errors. All errors will be collected and returned. Given the same schema as above,
|
|
161
150
|
|
|
162
151
|
**Code: Sub Schemas via Address**
|
|
@@ -214,12 +203,13 @@ Validation Failed {
|
|
|
214
203
|
"errors": [
|
|
215
204
|
{
|
|
216
205
|
"kind": "type",
|
|
206
|
+
"type": "number",
|
|
217
207
|
"message": "age is not a valid number",
|
|
218
|
-
"path": "age"
|
|
219
|
-
"type": "number"
|
|
208
|
+
"path": "age"
|
|
220
209
|
},
|
|
221
210
|
{
|
|
222
211
|
"kind": "required",
|
|
212
|
+
"active": true,
|
|
223
213
|
"message": "address.street2 is required",
|
|
224
214
|
"path": "address.street2"
|
|
225
215
|
}
|
|
@@ -228,7 +218,6 @@ Validation Failed {
|
|
|
228
218
|
```
|
|
229
219
|
|
|
230
220
|
### Custom Validators
|
|
231
|
-
|
|
232
221
|
Within the schema framework, it is possible to add custom validators class level. This allows for more flexibility when dealing with specific situations (e.g. password requirements or ensuring two fields match)
|
|
233
222
|
|
|
234
223
|
**Code: Password Validator**
|
|
@@ -281,6 +270,10 @@ export interface ValidationError {
|
|
|
281
270
|
* Regular expression to match
|
|
282
271
|
*/
|
|
283
272
|
re?: string;
|
|
273
|
+
/**
|
|
274
|
+
* Number to compare against
|
|
275
|
+
*/
|
|
276
|
+
n?: number | Date;
|
|
284
277
|
/**
|
|
285
278
|
* The type of the field
|
|
286
279
|
*/
|
|
@@ -289,7 +282,7 @@ export interface ValidationError {
|
|
|
289
282
|
```
|
|
290
283
|
|
|
291
284
|
## Custom Types
|
|
292
|
-
When working with the schema, the basic types are easily understood, but some of [Typescript](https://typescriptlang.org)'s more complex constructs are too complex to automate cleanly.
|
|
285
|
+
When working with the schema, the basic types are easily understood, but some of [Typescript](https://typescriptlang.org)'s more complex constructs are too complex to automate cleanly.
|
|
293
286
|
|
|
294
287
|
To that end, the module supports two concepts:
|
|
295
288
|
|
|
@@ -324,8 +317,6 @@ export class PointImpl {
|
|
|
324
317
|
```
|
|
325
318
|
|
|
326
319
|
What you can see here is that the `Point` type is now backed by a class that supports:
|
|
327
|
-
|
|
328
|
-
|
|
329
320
|
* `validateSchema` - Will run during validation for this specific type.
|
|
330
321
|
* `bindSchema` - Will run during binding to ensure correct behavior.
|
|
331
322
|
|
|
@@ -355,9 +346,9 @@ Validation Failed {
|
|
|
355
346
|
"errors": [
|
|
356
347
|
{
|
|
357
348
|
"kind": "type",
|
|
349
|
+
"type": "PointImpl",
|
|
358
350
|
"message": "point is not a valid PointImpl",
|
|
359
|
-
"path": "point"
|
|
360
|
-
"type": "PointImpl"
|
|
351
|
+
"path": "point"
|
|
361
352
|
}
|
|
362
353
|
]
|
|
363
354
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/schema",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.1.0-rc.0",
|
|
4
4
|
"description": "Data type registry for runtime validation, reflection and binding.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"directory": "module/schema"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/registry": "^3.0.
|
|
30
|
+
"@travetto/registry": "^3.1.0-rc.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@travetto/transformer": "^3.0.
|
|
33
|
+
"@travetto/transformer": "^3.1.0-rc.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@travetto/transformer": {
|
package/src/service/registry.ts
CHANGED
|
@@ -233,7 +233,7 @@ class $SchemaRegistry extends MetadataRegistry<ClassConfig, FieldConfig> {
|
|
|
233
233
|
const { fields, schema } = this.getViewSchema(cls);
|
|
234
234
|
const out = [];
|
|
235
235
|
for (const el of fields) {
|
|
236
|
-
if (el.startsWith(`${method}.`)) {
|
|
236
|
+
if (el.startsWith(`${method}.`) && schema[el].forMethod) {
|
|
237
237
|
out.push(schema[el]);
|
|
238
238
|
}
|
|
239
239
|
}
|
|
@@ -302,6 +302,7 @@ class $SchemaRegistry extends MetadataRegistry<ClassConfig, FieldConfig> {
|
|
|
302
302
|
registerPendingParamConfig(target: Class, method: string, idx: number, type: ClassList, conf?: Partial<FieldConfig>): Class {
|
|
303
303
|
conf ??= {};
|
|
304
304
|
conf.index = idx;
|
|
305
|
+
conf.forMethod = true;
|
|
305
306
|
return this.registerPendingFieldConfig(target, `${method}.${idx}`, type, conf);
|
|
306
307
|
}
|
|
307
308
|
|
package/src/service/types.ts
CHANGED
|
@@ -160,6 +160,10 @@ export interface FieldConfig extends DescribableConfig {
|
|
|
160
160
|
* Is this field a getter or setter
|
|
161
161
|
*/
|
|
162
162
|
accessor?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Is the field for a method
|
|
165
|
+
*/
|
|
166
|
+
forMethod?: boolean;
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
export type ViewFieldsConfig<T> = { with: Extract<(keyof T), string>[] } | { without: Extract<(keyof T), string>[] };
|
package/src/validate/types.ts
CHANGED
|
@@ -25,6 +25,10 @@ export interface ValidationError {
|
|
|
25
25
|
* Regular expression to match
|
|
26
26
|
*/
|
|
27
27
|
re?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Number to compare against
|
|
30
|
+
*/
|
|
31
|
+
n?: number | Date;
|
|
28
32
|
/**
|
|
29
33
|
* The type of the field
|
|
30
34
|
*/
|
|
@@ -55,6 +59,10 @@ export interface ValidationResult {
|
|
|
55
59
|
* Potential regular expression for the result
|
|
56
60
|
*/
|
|
57
61
|
re?: RegExp;
|
|
62
|
+
/**
|
|
63
|
+
* Number to compare against
|
|
64
|
+
*/
|
|
65
|
+
n?: number | Date;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
/**
|
|
@@ -40,7 +40,7 @@ export class SchemaValidator {
|
|
|
40
40
|
|
|
41
41
|
const fields = TypedObject.keys<SchemaConfig>(schema);
|
|
42
42
|
for (const field of fields) {
|
|
43
|
-
if (schema[field].access !== 'readonly') { // Do not validate readonly fields
|
|
43
|
+
if (schema[field].access !== 'readonly' && !schema[field].forMethod) { // Do not validate readonly fields
|
|
44
44
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
45
45
|
errors = errors.concat(this.#validateFieldSchema(schema[field], o[field as keyof T], relative));
|
|
46
46
|
}
|
|
@@ -202,6 +202,7 @@ export class SchemaValidator {
|
|
|
202
202
|
const out: ValidationError[] = [];
|
|
203
203
|
for (const res of results) {
|
|
204
204
|
const err: ValidationError = {
|
|
205
|
+
...res,
|
|
205
206
|
kind: res.kind,
|
|
206
207
|
value: res.value,
|
|
207
208
|
message: '',
|
|
@@ -311,7 +312,7 @@ export class SchemaValidator {
|
|
|
311
312
|
* @param method The method being invoked
|
|
312
313
|
* @param params The params to validate
|
|
313
314
|
*/
|
|
314
|
-
static validateMethod<T>(cls: Class<T>, method: string, params: unknown[]): void {
|
|
315
|
+
static async validateMethod<T>(cls: Class<T>, method: string, params: unknown[]): Promise<void> {
|
|
315
316
|
const errors: ValidationError[] = [];
|
|
316
317
|
for (const field of SchemaRegistry.getMethodSchema(cls, method)) {
|
|
317
318
|
errors.push(...this.#validateFieldSchema(field, params[field.index!]));
|
|
@@ -128,6 +128,12 @@ export class SchemaTransformUtil {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
const tags = ts.getJSDocTags(node);
|
|
132
|
+
const aliases = tags.filter(x => x.tagName.getText() === 'alias');
|
|
133
|
+
if (aliases.length) {
|
|
134
|
+
attrs.push(state.factory.createPropertyAssignment('aliases', state.fromLiteral(aliases.map(x => x.comment).filter(x => !!x))));
|
|
135
|
+
}
|
|
136
|
+
|
|
131
137
|
const params: ts.Expression[] = [];
|
|
132
138
|
|
|
133
139
|
const existing = state.findDecorator('@travetto/schema', node, 'Field', FIELD_MOD);
|