@travetto/schema 3.1.9 → 3.2.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 CHANGED
@@ -36,6 +36,7 @@ export class User {
36
36
  name: string;
37
37
  age: number;
38
38
  favoriteFood?: 'pizza' | 'burrito' | 'salad';
39
+ height?: `${number}${'m' | 'ft'}`;
39
40
  }
40
41
  ```
41
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/schema",
3
- "version": "3.1.9",
3
+ "version": "3.2.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.1.5"
30
+ "@travetto/registry": "^3.2.0-rc.0"
31
31
  },
32
32
  "peerDependencies": {
33
- "@travetto/transformer": "^3.1.5"
33
+ "@travetto/transformer": "^3.2.0-rc.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@travetto/transformer": {
@@ -5,6 +5,9 @@ import { ValidatorFn } from '../validate/types';
5
5
 
6
6
  export type ClassList = Class | [Class];
7
7
 
8
+ type TemplateLiteralPart = string | NumberConstructor | StringConstructor | BooleanConstructor;
9
+ export type TemplateLiteral = { op: 'and' | 'or', values: (TemplateLiteralPart | TemplateLiteral)[] };
10
+
8
11
  /**
9
12
  * Basic describable configuration
10
13
  */
@@ -135,7 +138,7 @@ export interface FieldConfig extends DescribableConfig {
135
138
  /**
136
139
  * Does the field expect a match
137
140
  */
138
- match?: { re: RegExp, message?: string };
141
+ match?: { re: RegExp, message?: string, template?: TemplateLiteral };
139
142
  /**
140
143
  * Minimum value configuration
141
144
  */
@@ -1,5 +1,8 @@
1
1
  import ts from 'typescript';
2
- import { type AnyType, DeclarationUtil, DecoratorUtil, DocUtil, ParamDocumentation, TransformerState } from '@travetto/transformer';
2
+ import {
3
+ type AnyType, DeclarationUtil, LiteralUtil,
4
+ DecoratorUtil, DocUtil, ParamDocumentation, TransformerState
5
+ } from '@travetto/transformer';
3
6
 
4
7
  const SCHEMA_MOD = '@travetto/schema/src/decorator/schema';
5
8
  const FIELD_MOD = '@travetto/schema/src/decorator/field';
@@ -15,6 +18,7 @@ export class SchemaTransformUtil {
15
18
  case 'pointer': return this.toConcreteType(state, type.target, node, root);
16
19
  case 'managed': return state.getOrImport(type);
17
20
  case 'tuple': return state.fromLiteral(type.subTypes.map(x => this.toConcreteType(state, x, node, root)!));
21
+ case 'template': return state.createIdentifier(type.ctor.name);
18
22
  case 'literal': {
19
23
  if ((type.ctor === Array) && type.typeArguments?.length) {
20
24
  return state.fromLiteral([this.toConcreteType(state, type.typeArguments[0], node, root)]);
@@ -108,18 +112,28 @@ export class SchemaTransformUtil {
108
112
  ));
109
113
  }
110
114
 
115
+ const primaryExpr = typeExpr.key === 'literal' && typeExpr.typeArguments?.[0] ? typeExpr.typeArguments[0] : typeExpr;
116
+
117
+ // We need to ensure we aren't being tripped up by the wrapper for arrays, sets, etc.
111
118
  // If we have a union type
112
- if (typeExpr.key === 'union') {
113
- const values = typeExpr.subTypes.map(x => x.key === 'literal' ? x.value : undefined)
119
+ if (primaryExpr.key === 'union') {
120
+ const values = primaryExpr.subTypes.map(x => x.key === 'literal' ? x.value : undefined)
114
121
  .filter(x => x !== undefined && x !== null)
115
122
  .sort();
116
123
 
117
- if (values.length === typeExpr.subTypes.length) {
124
+ if (values.length === primaryExpr.subTypes.length) {
118
125
  attrs.push(state.factory.createPropertyAssignment('enum', state.fromLiteral({
119
126
  values,
120
127
  message: `{path} is only allowed to be "${values.join('" or "')}"`
121
128
  })));
122
129
  }
130
+ } else if (primaryExpr.key === 'template' && primaryExpr.template) {
131
+ const re = LiteralUtil.templateLiteralToRegex(primaryExpr.template);
132
+ attrs.push(state.factory.createPropertyAssignment('match', state.fromLiteral({
133
+ re: new RegExp(re),
134
+ template: primaryExpr.template,
135
+ message: `{path} must match "${re}"`
136
+ })));
123
137
  }
124
138
 
125
139
  if (ts.isParameter(node)) {
@@ -212,6 +226,7 @@ export class SchemaTransformUtil {
212
226
  switch (type?.key) {
213
227
  case 'managed': out.type = state.typeToIdentifier(type); break;
214
228
  case 'shape': out.type = this.toConcreteType(state, type, target); break;
229
+ case 'template': out.type = state.factory.createIdentifier(type.ctor.name); break;
215
230
  case 'literal': {
216
231
  if (type.ctor) {
217
232
  out.type = out.array ?